Merge "Notify TrustAgentService when device policy configuration no longer applies"
diff --git a/Android.mk b/Android.mk
index f3f1acb..e42a2f8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -238,6 +238,8 @@
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
 	core/java/android/service/wallpaper/IWallpaperEngine.aidl \
 	core/java/android/service/wallpaper/IWallpaperService.aidl \
+	core/java/android/service/chooser/IChooserTargetService.aidl \
+	core/java/android/service/chooser/IChooserTargetResult.aidl \
 	core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
 	core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
 	core/java/android/view/accessibility/IAccessibilityManager.aidl \
@@ -333,8 +335,8 @@
 	media/java/android/media/IRingtonePlayer.aidl \
 	media/java/android/media/IVolumeController.aidl \
 	media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl \
+	media/java/android/media/midi/IMidiDeviceListener.aidl \
 	media/java/android/media/midi/IMidiDeviceServer.aidl \
-	media/java/android/media/midi/IMidiListener.aidl \
 	media/java/android/media/midi/IMidiManager.aidl \
 	media/java/android/media/projection/IMediaProjection.aidl \
 	media/java/android/media/projection/IMediaProjectionCallback.aidl \
@@ -545,6 +547,7 @@
 	frameworks/base/core/java/android/view/textservice/SuggestionsInfo.aidl \
 	frameworks/base/core/java/android/service/carrier/MessagePdu.aidl \
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
+	frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
 	frameworks/base/core/java/android/app/usage/UsageEvents.aidl \
 	frameworks/base/core/java/android/app/Notification.aidl \
diff --git a/api/current.txt b/api/current.txt
index 707999b..11db5c3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21,6 +21,7 @@
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
     field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+    field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
@@ -3544,6 +3545,7 @@
     method public int getLargeMemoryClass();
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
+    method public int getLockTaskModeState();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -3554,7 +3556,7 @@
     method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
     method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
-    method public boolean isInLockTaskMode();
+    method public deprecated boolean isInLockTaskMode();
     method public boolean isLowRamDevice();
     method public static boolean isRunningInTestHarness();
     method public static boolean isUserAMonkey();
@@ -3562,6 +3564,9 @@
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
+    field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
+    field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
+    field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
     field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
     field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -4459,10 +4464,10 @@
     method public void setInTouchMode(boolean);
     method public void start();
     method public android.app.Activity startActivitySync(android.content.Intent);
-    method public void startAllocCounting();
+    method public deprecated void startAllocCounting();
     method public void startPerformanceSnapshot();
     method public void startProfiling();
-    method public void stopAllocCounting();
+    method public deprecated void stopAllocCounting();
     method public void stopProfiling();
     method public void waitForIdle(java.lang.Runnable);
     method public void waitForIdleSync();
@@ -5364,6 +5369,7 @@
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
+    method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
@@ -5429,6 +5435,7 @@
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
     method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
     method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
+    method public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
     method public void onReceive(android.content.Context, android.content.Intent);
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -5440,6 +5447,7 @@
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final java.lang.String ACTION_READY_FOR_USER_INITIALIZATION = "android.app.action.READY_FOR_USER_INITIALIZATION";
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
@@ -5451,6 +5459,7 @@
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
+    method public void clearDeviceInitializerApp(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
@@ -5487,6 +5496,7 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
+    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5494,6 +5504,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isDeviceInitializerApp(java.lang.String);
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5510,6 +5521,7 @@
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
+    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
@@ -5535,7 +5547,10 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
+    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setUserEnabled(android.content.ComponentName);
+    method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
@@ -5553,10 +5568,15 @@
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
     field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
@@ -10953,6 +10973,8 @@
   public class ImageFormat {
     ctor public ImageFormat();
     method public static int getBitsPerPixel(int);
+    field public static final int DEPTH16 = 1144402265; // 0x44363159
+    field public static final int DEPTH_POINT_CLOUD = 257; // 0x101
     field public static final int JPEG = 256; // 0x100
     field public static final int NV16 = 16; // 0x10
     field public static final int NV21 = 17; // 0x11
@@ -22025,47 +22047,47 @@
     method public static final int getBinderProxyObjectCount();
     method public static int getBinderReceivedTransactions();
     method public static int getBinderSentTransactions();
-    method public static int getGlobalAllocCount();
-    method public static int getGlobalAllocSize();
-    method public static int getGlobalClassInitCount();
-    method public static int getGlobalClassInitTime();
+    method public static deprecated int getGlobalAllocCount();
+    method public static deprecated int getGlobalAllocSize();
+    method public static deprecated int getGlobalClassInitCount();
+    method public static deprecated int getGlobalClassInitTime();
     method public static deprecated int getGlobalExternalAllocCount();
     method public static deprecated int getGlobalExternalAllocSize();
     method public static deprecated int getGlobalExternalFreedCount();
     method public static deprecated int getGlobalExternalFreedSize();
-    method public static int getGlobalFreedCount();
-    method public static int getGlobalFreedSize();
-    method public static int getGlobalGcInvocationCount();
+    method public static deprecated int getGlobalFreedCount();
+    method public static deprecated int getGlobalFreedSize();
+    method public static deprecated int getGlobalGcInvocationCount();
     method public static int getLoadedClassCount();
     method public static void getMemoryInfo(android.os.Debug.MemoryInfo);
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
     method public static long getPss();
-    method public static int getThreadAllocCount();
-    method public static int getThreadAllocSize();
+    method public static deprecated int getThreadAllocCount();
+    method public static deprecated int getThreadAllocSize();
     method public static deprecated int getThreadExternalAllocCount();
     method public static deprecated int getThreadExternalAllocSize();
-    method public static int getThreadGcInvocationCount();
+    method public static deprecated int getThreadGcInvocationCount();
     method public static boolean isDebuggerConnected();
     method public static void printLoadedClasses(int);
-    method public static void resetAllCounts();
-    method public static void resetGlobalAllocCount();
-    method public static void resetGlobalAllocSize();
-    method public static void resetGlobalClassInitCount();
-    method public static void resetGlobalClassInitTime();
+    method public static deprecated void resetAllCounts();
+    method public static deprecated void resetGlobalAllocCount();
+    method public static deprecated void resetGlobalAllocSize();
+    method public static deprecated void resetGlobalClassInitCount();
+    method public static deprecated void resetGlobalClassInitTime();
     method public static deprecated void resetGlobalExternalAllocCount();
     method public static deprecated void resetGlobalExternalAllocSize();
     method public static deprecated void resetGlobalExternalFreedCount();
     method public static deprecated void resetGlobalExternalFreedSize();
-    method public static void resetGlobalFreedCount();
-    method public static void resetGlobalFreedSize();
-    method public static void resetGlobalGcInvocationCount();
-    method public static void resetThreadAllocCount();
-    method public static void resetThreadAllocSize();
+    method public static deprecated void resetGlobalFreedCount();
+    method public static deprecated void resetGlobalFreedSize();
+    method public static deprecated void resetGlobalGcInvocationCount();
+    method public static deprecated void resetThreadAllocCount();
+    method public static deprecated void resetThreadAllocSize();
     method public static deprecated void resetThreadExternalAllocCount();
     method public static deprecated void resetThreadExternalAllocSize();
-    method public static void resetThreadGcInvocationCount();
+    method public static deprecated void resetThreadGcInvocationCount();
     method public static deprecated int setAllocationLimit(int);
     method public static deprecated int setGlobalAllocationLimit(int);
     method public static deprecated void startAllocCounting();
@@ -22084,7 +22106,7 @@
     field public static final int SHOW_CLASSLOADER = 2; // 0x2
     field public static final int SHOW_FULL_DETAIL = 1; // 0x1
     field public static final int SHOW_INITIALIZED = 4; // 0x4
-    field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1
+    field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1
   }
 
   public static deprecated class Debug.InstructionCount {
@@ -24040,6 +24062,7 @@
     field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
     field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
     field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
+    field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -24899,6 +24922,7 @@
     field public static final int ORGANIZATION = 30; // 0x1e
     field public static final int PHONE = 20; // 0x14
     field public static final int STRUCTURED_NAME = 40; // 0x28
+    field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25
     field public static final int UNDEFINED = 0; // 0x0
   }
 
@@ -25907,7 +25931,6 @@
     field public static final deprecated java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
     field public static final deprecated java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
@@ -25970,14 +25993,6 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
-    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
-    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
-    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
-    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
-    field public static final java.lang.String VOLUME_RING = "volume_ring";
-    field public static final java.lang.String[] VOLUME_SETTINGS;
-    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
-    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
     field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
     field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
@@ -27449,6 +27464,30 @@
 
 }
 
+package android.service.chooser {
+
+  public final class ChooserTarget implements android.os.Parcelable {
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+    method public int describeContents();
+    method public android.graphics.Bitmap getIcon();
+    method public android.content.IntentSender getIntentSender();
+    method public float getScore();
+    method public java.lang.CharSequence getTitle();
+    method public boolean sendIntent(android.content.Context, android.content.Intent);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
+  }
+
+  public abstract class ChooserTargetService extends android.app.Service {
+    ctor public ChooserTargetService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+  }
+
+}
+
 package android.service.dreams {
 
   public class DreamService extends android.app.Service implements android.view.Window.Callback {
@@ -29290,6 +29329,7 @@
   }
 
   public class TelephonyManager {
+    method public boolean canChangeDtmfToneLength();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
     method public android.telephony.CellLocation getCellLocation();
@@ -29325,6 +29365,7 @@
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
     method public boolean isVoiceCapable();
+    method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
@@ -36884,6 +36925,12 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public abstract class WebResourceError {
+    ctor public WebResourceError();
+    method public abstract java.lang.String getDescription();
+    method public abstract int getErrorCode();
+  }
+
   public abstract interface WebResourceRequest {
     method public abstract java.lang.String getMethod();
     method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders();
@@ -36892,7 +36939,7 @@
     method public abstract boolean isForMainFrame();
   }
 
-  public class WebResourceResponse {
+  public class WebResourceResponse extends android.webkit.WebResourceResponseBase {
     ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream);
     ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
     method public java.io.InputStream getData();
@@ -36908,6 +36955,16 @@
     method public void setStatusCodeAndReasonPhrase(int, java.lang.String);
   }
 
+  public abstract class WebResourceResponseBase {
+    ctor public WebResourceResponseBase();
+    method public abstract java.io.InputStream getData();
+    method public abstract java.lang.String getEncoding();
+    method public abstract java.lang.String getMimeType();
+    method public abstract java.lang.String getReasonPhrase();
+    method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders();
+    method public abstract int getStatusCode();
+  }
+
   public abstract class WebSettings {
     ctor public WebSettings();
     method public abstract deprecated boolean enableSmoothTransition();
@@ -37222,8 +37279,10 @@
     method public void onPageFinished(android.webkit.WebView, java.lang.String);
     method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
     method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
-    method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
     method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
+    method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase);
     method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
     method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
     method public void onScaleChanged(android.webkit.WebView, float, float);
@@ -37236,6 +37295,7 @@
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
     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_BLOCKED = -16; // 0xfffffff0
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
     field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
     field public static final int ERROR_FILE = -13; // 0xfffffff3
diff --git a/api/removed.txt b/api/removed.txt
index 8668a77..1b209a9 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -34,6 +34,22 @@
 
 }
 
+package android.provider {
+
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
+    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
+    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
+    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
+    field public static final java.lang.String VOLUME_RING = "volume_ring";
+    field public static final java.lang.String[] VOLUME_SETTINGS;
+    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
+    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index 2ffc4e1..da5986f5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -29,6 +29,7 @@
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
     field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+    field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
     field public static final java.lang.String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
     field public static final java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
@@ -3632,6 +3633,7 @@
     method public int getLargeMemoryClass();
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
+    method public int getLockTaskModeState();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -3642,7 +3644,7 @@
     method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
     method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
-    method public boolean isInLockTaskMode();
+    method public deprecated boolean isInLockTaskMode();
     method public boolean isLowRamDevice();
     method public static boolean isRunningInTestHarness();
     method public static boolean isUserAMonkey();
@@ -3650,6 +3652,9 @@
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
+    field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
+    field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
+    field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
     field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
     field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -4549,10 +4554,10 @@
     method public void setInTouchMode(boolean);
     method public void start();
     method public android.app.Activity startActivitySync(android.content.Intent);
-    method public void startAllocCounting();
+    method public deprecated void startAllocCounting();
     method public void startPerformanceSnapshot();
     method public void startProfiling();
-    method public void stopAllocCounting();
+    method public deprecated void stopAllocCounting();
     method public void stopProfiling();
     method public void waitForIdle(java.lang.Runnable);
     method public void waitForIdleSync();
@@ -5455,6 +5460,7 @@
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
+    method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
@@ -5523,6 +5529,7 @@
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
     method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
     method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
+    method public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
     method public void onReceive(android.content.Context, android.content.Intent);
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -5534,6 +5541,7 @@
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final java.lang.String ACTION_READY_FOR_USER_INITIALIZATION = "android.app.action.READY_FOR_USER_INITIALIZATION";
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
@@ -5545,6 +5553,7 @@
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
+    method public void clearDeviceInitializerApp(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
@@ -5561,6 +5570,7 @@
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
     method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
+    method public java.lang.String getDeviceInitializerApp();
     method public java.lang.String getDeviceOwner();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -5587,6 +5597,7 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
+    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5594,6 +5605,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isDeviceInitializerApp(java.lang.String);
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5611,6 +5623,7 @@
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
+    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
@@ -5636,7 +5649,10 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
+    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setUserEnabled(android.content.ComponentName);
+    method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
@@ -5656,10 +5672,15 @@
     field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
@@ -11227,6 +11248,8 @@
   public class ImageFormat {
     ctor public ImageFormat();
     method public static int getBitsPerPixel(int);
+    field public static final int DEPTH16 = 1144402265; // 0x44363159
+    field public static final int DEPTH_POINT_CLOUD = 257; // 0x101
     field public static final int JPEG = 256; // 0x100
     field public static final int NV16 = 16; // 0x10
     field public static final int NV21 = 17; // 0x11
@@ -15118,6 +15141,7 @@
 
   public final class AudioAttributes implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAllFlags();
     method public int getCapturePreset();
     method public int getContentType();
     method public int getFlags();
@@ -15159,6 +15183,7 @@
     method public android.media.AudioAttributes.Builder setCapturePreset(int);
     method public android.media.AudioAttributes.Builder setContentType(int);
     method public android.media.AudioAttributes.Builder setFlags(int);
+    method public android.media.AudioAttributes.Builder setInternalCapturePreset(int);
     method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
     method public android.media.AudioAttributes.Builder setUsage(int);
   }
@@ -15391,6 +15416,7 @@
 
   public class AudioRecord {
     ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
@@ -16529,7 +16555,9 @@
   public final class MediaRecorder.AudioSource {
     field public static final int CAMCORDER = 5; // 0x5
     field public static final int DEFAULT = 0; // 0x0
+    field public static final int HOTWORD = 1999; // 0x7cf
     field public static final int MIC = 1; // 0x1
+    field public static final int RADIO_TUNER = 1998; // 0x7ce
     field public static final int REMOTE_SUBMIX = 8; // 0x8
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
@@ -23614,47 +23642,47 @@
     method public static final int getBinderProxyObjectCount();
     method public static int getBinderReceivedTransactions();
     method public static int getBinderSentTransactions();
-    method public static int getGlobalAllocCount();
-    method public static int getGlobalAllocSize();
-    method public static int getGlobalClassInitCount();
-    method public static int getGlobalClassInitTime();
+    method public static deprecated int getGlobalAllocCount();
+    method public static deprecated int getGlobalAllocSize();
+    method public static deprecated int getGlobalClassInitCount();
+    method public static deprecated int getGlobalClassInitTime();
     method public static deprecated int getGlobalExternalAllocCount();
     method public static deprecated int getGlobalExternalAllocSize();
     method public static deprecated int getGlobalExternalFreedCount();
     method public static deprecated int getGlobalExternalFreedSize();
-    method public static int getGlobalFreedCount();
-    method public static int getGlobalFreedSize();
-    method public static int getGlobalGcInvocationCount();
+    method public static deprecated int getGlobalFreedCount();
+    method public static deprecated int getGlobalFreedSize();
+    method public static deprecated int getGlobalGcInvocationCount();
     method public static int getLoadedClassCount();
     method public static void getMemoryInfo(android.os.Debug.MemoryInfo);
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
     method public static long getPss();
-    method public static int getThreadAllocCount();
-    method public static int getThreadAllocSize();
+    method public static deprecated int getThreadAllocCount();
+    method public static deprecated int getThreadAllocSize();
     method public static deprecated int getThreadExternalAllocCount();
     method public static deprecated int getThreadExternalAllocSize();
-    method public static int getThreadGcInvocationCount();
+    method public static deprecated int getThreadGcInvocationCount();
     method public static boolean isDebuggerConnected();
     method public static void printLoadedClasses(int);
-    method public static void resetAllCounts();
-    method public static void resetGlobalAllocCount();
-    method public static void resetGlobalAllocSize();
-    method public static void resetGlobalClassInitCount();
-    method public static void resetGlobalClassInitTime();
+    method public static deprecated void resetAllCounts();
+    method public static deprecated void resetGlobalAllocCount();
+    method public static deprecated void resetGlobalAllocSize();
+    method public static deprecated void resetGlobalClassInitCount();
+    method public static deprecated void resetGlobalClassInitTime();
     method public static deprecated void resetGlobalExternalAllocCount();
     method public static deprecated void resetGlobalExternalAllocSize();
     method public static deprecated void resetGlobalExternalFreedCount();
     method public static deprecated void resetGlobalExternalFreedSize();
-    method public static void resetGlobalFreedCount();
-    method public static void resetGlobalFreedSize();
-    method public static void resetGlobalGcInvocationCount();
-    method public static void resetThreadAllocCount();
-    method public static void resetThreadAllocSize();
+    method public static deprecated void resetGlobalFreedCount();
+    method public static deprecated void resetGlobalFreedSize();
+    method public static deprecated void resetGlobalGcInvocationCount();
+    method public static deprecated void resetThreadAllocCount();
+    method public static deprecated void resetThreadAllocSize();
     method public static deprecated void resetThreadExternalAllocCount();
     method public static deprecated void resetThreadExternalAllocSize();
-    method public static void resetThreadGcInvocationCount();
+    method public static deprecated void resetThreadGcInvocationCount();
     method public static deprecated int setAllocationLimit(int);
     method public static deprecated int setGlobalAllocationLimit(int);
     method public static deprecated void startAllocCounting();
@@ -23673,7 +23701,7 @@
     field public static final int SHOW_CLASSLOADER = 2; // 0x2
     field public static final int SHOW_FULL_DETAIL = 1; // 0x1
     field public static final int SHOW_INITIALIZED = 4; // 0x4
-    field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1
+    field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1
   }
 
   public static deprecated class Debug.InstructionCount {
@@ -25639,6 +25667,7 @@
     field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
     field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
     field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
+    field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -26498,6 +26527,7 @@
     field public static final int ORGANIZATION = 30; // 0x1e
     field public static final int PHONE = 20; // 0x14
     field public static final int STRUCTURED_NAME = 40; // 0x28
+    field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25
     field public static final int UNDEFINED = 0; // 0x0
   }
 
@@ -27507,7 +27537,6 @@
     field public static final deprecated java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
     field public static final deprecated java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
@@ -27570,14 +27599,6 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
-    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
-    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
-    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
-    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
-    field public static final java.lang.String VOLUME_RING = "volume_ring";
-    field public static final java.lang.String[] VOLUME_SETTINGS;
-    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
-    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
     field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
     field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
@@ -29049,6 +29070,30 @@
 
 }
 
+package android.service.chooser {
+
+  public final class ChooserTarget implements android.os.Parcelable {
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+    method public int describeContents();
+    method public android.graphics.Bitmap getIcon();
+    method public android.content.IntentSender getIntentSender();
+    method public float getScore();
+    method public java.lang.CharSequence getTitle();
+    method public boolean sendIntent(android.content.Context, android.content.Intent);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
+  }
+
+  public abstract class ChooserTargetService extends android.app.Service {
+    ctor public ChooserTargetService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+  }
+
+}
+
 package android.service.dreams {
 
   public class DreamService extends android.app.Service implements android.view.Window.Callback {
@@ -30894,8 +30939,8 @@
     method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
-    field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
+    field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
@@ -31416,6 +31461,7 @@
   public class TelephonyManager {
     method public void answerRingingCall();
     method public void call(java.lang.String, java.lang.String);
+    method public boolean canChangeDtmfToneLength();
     method public int checkCarrierPrivilegesForPackage(java.lang.String);
     method public void dial(java.lang.String);
     method public boolean disableDataConnectivity();
@@ -31475,6 +31521,7 @@
     method public boolean isSmsCapable();
     method public boolean isVideoCallingEnabled();
     method public boolean isVoiceCapable();
+    method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public boolean needsOtaServiceProvisioning();
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
@@ -39107,6 +39154,12 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public abstract class WebResourceError {
+    ctor public WebResourceError();
+    method public abstract java.lang.String getDescription();
+    method public abstract int getErrorCode();
+  }
+
   public abstract interface WebResourceRequest {
     method public abstract java.lang.String getMethod();
     method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders();
@@ -39115,7 +39168,7 @@
     method public abstract boolean isForMainFrame();
   }
 
-  public class WebResourceResponse {
+  public class WebResourceResponse extends android.webkit.WebResourceResponseBase {
     ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream);
     ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
     method public java.io.InputStream getData();
@@ -39131,6 +39184,16 @@
     method public void setStatusCodeAndReasonPhrase(int, java.lang.String);
   }
 
+  public abstract class WebResourceResponseBase {
+    ctor public WebResourceResponseBase();
+    method public abstract java.io.InputStream getData();
+    method public abstract java.lang.String getEncoding();
+    method public abstract java.lang.String getMimeType();
+    method public abstract java.lang.String getReasonPhrase();
+    method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders();
+    method public abstract int getStatusCode();
+  }
+
   public abstract class WebSettings {
     ctor public WebSettings();
     method public abstract deprecated boolean enableSmoothTransition();
@@ -39490,8 +39553,10 @@
     method public void onPageFinished(android.webkit.WebView, java.lang.String);
     method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
     method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
-    method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
     method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
+    method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase);
     method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
     method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
     method public void onScaleChanged(android.webkit.WebView, float, float);
@@ -39504,6 +39569,7 @@
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
     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_BLOCKED = -16; // 0xfffffff0
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
     field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
     field public static final int ERROR_FILE = -13; // 0xfffffff3
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 8668a77..1b209a9 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -34,6 +34,22 @@
 
 }
 
+package android.provider {
+
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
+    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
+    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
+    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
+    field public static final java.lang.String VOLUME_RING = "volume_ring";
+    field public static final java.lang.String[] VOLUME_SETTINGS;
+    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
+    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bc0c451..29ba1d7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -117,6 +117,8 @@
                 "       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
                 "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
                 "       am clear-debug-app\n" +
+                "       am set-watch-heap <PROCESS> <MEM-LIMIT>\n" +
+                "       am clear-watch-heap\n" +
                 "       am monitor [--gdb <port>]\n" +
                 "       am hang [--allow-restart]\n" +
                 "       am restart\n" +
@@ -211,6 +213,11 @@
                 "\n" +
                 "am clear-debug-app: clear the previously set-debug-app.\n" +
                 "\n" +
+                "am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or\n" +
+                "    above <HEAP-LIMIT> then a heap dump is collected for the user to report\n" +
+                "\n" +
+                "am clear-watch-heap: clear the previously set-watch-heap.\n" +
+                "\n" +
                 "am bug-report: request bug report generation; will launch UI\n" +
                 "    when done to select where it should be delivered.\n" +
                 "\n" +
@@ -342,6 +349,10 @@
             runSetDebugApp();
         } else if (op.equals("clear-debug-app")) {
             runClearDebugApp();
+        } else if (op.equals("set-watch-heap")) {
+            runSetWatchHeap();
+        } else if (op.equals("clear-watch-heap")) {
+            runClearWatchHeap();
         } else if (op.equals("bug-report")) {
             runBugReport();
         } else if (op.equals("monitor")) {
@@ -1172,6 +1183,17 @@
         mAm.setDebugApp(null, false, true);
     }
 
+    private void runSetWatchHeap() throws Exception {
+        String proc = nextArgRequired();
+        String limit = nextArgRequired();
+        mAm.setDumpHeapDebugLimit(proc, Long.parseLong(limit));
+    }
+
+    private void runClearWatchHeap() throws Exception {
+        String proc = nextArgRequired();
+        mAm.setDumpHeapDebugLimit(proc, -1);
+    }
+
     private void runBugReport() throws Exception {
         mAm.requestBugReport();
         System.out.println("Your lovely bug report is being created; please be patient.");
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index a31b150..c27d0c0 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -20,6 +20,7 @@
 import android.app.IActivityManager;
 import android.app.IActivityManager.ContentProviderHolder;
 import android.content.IContentProvider;
+import android.database.Cursor;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -29,13 +30,18 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 public final class SettingsCmd {
 
     enum CommandVerb {
         UNSPECIFIED,
         GET,
         PUT,
-        DELETE
+        DELETE,
+        LIST,
     }
 
     static String[] mArgs;
@@ -47,7 +53,7 @@
     String mValue = null;
 
     public static void main(String[] args) {
-        if (args == null || args.length < 3) {
+        if (args == null || args.length < 2) {
             printUsage();
             return;
         }
@@ -78,6 +84,8 @@
                         mVerb = CommandVerb.PUT;
                     } else if ("delete".equalsIgnoreCase(arg)) {
                         mVerb = CommandVerb.DELETE;
+                    } else if ("list".equalsIgnoreCase(arg)) {
+                        mVerb = CommandVerb.LIST;
                     } else {
                         // invalid
                         System.err.println("Invalid command: " + arg);
@@ -91,6 +99,10 @@
                         break;  // invalid
                     }
                     mTable = arg.toLowerCase();
+                    if (mVerb == CommandVerb.LIST) {
+                        valid = true;
+                        break;
+                    }
                 } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
                     mKey = arg;
                     if (mNextArg >= mArgs.length) {
@@ -144,6 +156,11 @@
                             System.out.println("Deleted "
                                     + deleteForUser(provider, mUser, mTable, mKey) + " rows");
                             break;
+                        case LIST:
+                            for (String line : listForUser(provider, mUser, mTable)) {
+                                System.out.println(line);
+                            }
+                            break;
                         default:
                             System.err.println("Unspecified command");
                             break;
@@ -164,6 +181,34 @@
         }
     }
 
+    private List<String> listForUser(IContentProvider provider, int userHandle, String table) {
+        final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI
+                : "secure".equals(table) ? Settings.Secure.CONTENT_URI
+                : "global".equals(table) ? Settings.Global.CONTENT_URI
+                : null;
+        final ArrayList<String> lines = new ArrayList<String>();
+        if (uri == null) {
+            return lines;
+        }
+        try {
+            final Cursor cursor = provider.query(resolveCallingPackage(), uri, null, null, null,
+                    null, null);
+            try {
+                while (cursor != null && cursor.moveToNext()) {
+                    lines.add(cursor.getString(1) + "=" + cursor.getString(2));
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+            Collections.sort(lines);
+        } catch (RemoteException e) {
+            System.err.println("List failed in " + table + " for user " + userHandle);
+        }
+        return lines;
+    }
+
     private String nextArg() {
         if (mNextArg >= mArgs.length) {
             return null;
@@ -244,6 +289,7 @@
         System.err.println("usage:  settings [--user NUM] get namespace key");
         System.err.println("        settings [--user NUM] put namespace key value");
         System.err.println("        settings [--user NUM] delete namespace key");
+        System.err.println("        settings [--user NUM] list namespace");
         System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
         System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
     }
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 87ad49b..3f71d51 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Path;
@@ -861,6 +862,7 @@
      *  <p>Overriders of this method should call the superclass method to cause
      *  internal mechanisms to be set up correctly.</p>
      */
+    @CallSuper
     @Override
     void initAnimation() {
         if (!mInitialized) {
@@ -961,6 +963,7 @@
      *
      * @param fraction The elapsed fraction of the animation.
      */
+    @CallSuper
     @Override
     void animateValue(float fraction) {
         final Object target = getTarget();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 118af64..85dc832 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.annotation.CallSuper;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -506,6 +507,7 @@
      *  <p>Overrides of this method should call the superclass method to ensure
      *  that internal mechanisms for the animation are set up correctly.</p>
      */
+    @CallSuper
     void initAnimation() {
         if (!mInitialized) {
             int numValues = mValues.length;
@@ -1375,6 +1377,7 @@
      *
      * @param fraction The elapsed fraction of the animation.
      */
+    @CallSuper
     void animateValue(float fraction) {
         fraction = mInterpolator.getInterpolation(fraction);
         mCurrentFraction = fraction;
diff --git a/core/java/android/annotation/CallSuper.java b/core/java/android/annotation/CallSuper.java
new file mode 100644
index 0000000..82e2723
--- /dev/null
+++ b/core/java/android/annotation/CallSuper.java
@@ -0,0 +1,38 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that any overriding methods should invoke this method as well.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  &#64;CallSuper
+ *  public abstract void onFocusLost();
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CallSuper {
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/CheckResult.java b/core/java/android/annotation/CheckResult.java
new file mode 100644
index 0000000..787514e
--- /dev/null
+++ b/core/java/android/annotation/CheckResult.java
@@ -0,0 +1,58 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated method returns a result that it typically is
+ * an error to ignore. This is usually used for methods that have no side effect,
+ * so calling it without actually looking at the result usually means the developer
+ * has misunderstood what the method does.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  public &#64;CheckResult String trim(String s) { return s.trim(); }
+ *  ...
+ *  s.trim(); // this is probably an error
+ *  s = s.trim(); // ok
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CheckResult {
+    /** Defines the name of the suggested method to use instead, if applicable (using
+     * the same signature format as javadoc.) If there is more than one possibility,
+     * list them all separated by commas.
+     * <p>
+     * For example, ProcessBuilder has a method named {@code redirectErrorStream()}
+     * which sounds like it might redirect the error stream. It does not. It's just
+     * a getter which returns whether the process builder will redirect the error stream,
+     * and to actually set it, you must call {@code redirectErrorStream(boolean)}.
+     * In that case, the method should be defined like this:
+     * <pre>
+     *  &#64;CheckResult(suggest="#redirectErrorStream(boolean)")
+     *  public boolean redirectErrorStream() { ... }
+     * </pre>
+     */
+    String suggest() default "";
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java
new file mode 100644
index 0000000..c4c93ee
--- /dev/null
+++ b/core/java/android/annotation/ColorInt.java
@@ -0,0 +1,40 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element represents a packed color
+ * int, {@code AARRGGBB}. If applied to an int array, every element
+ * in the array represents a color integer.
+ * <p>
+ *  public abstract void setTextColor(&#64;ColorInt int color);
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD})
+public @interface ColorInt {
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/FloatRange.java b/core/java/android/annotation/FloatRange.java
new file mode 100644
index 0000000..3a7c150
--- /dev/null
+++ b/core/java/android/annotation/FloatRange.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 android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be a float or double in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  &#64;FloatRange(from=0.0,to=1.0)
+ *  public float getAlpha() {
+ *      ...
+ *  }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface FloatRange {
+    /** Smallest value. Whether it is inclusive or not is determined
+     * by {@link #fromInclusive} */
+    double from() default Double.NEGATIVE_INFINITY;
+    /** Largest value. Whether it is inclusive or not is determined
+     * by {@link #toInclusive} */
+    double to() default Double.POSITIVE_INFINITY;
+
+    /** Whether the from value is included in the range */
+    boolean fromInclusive() default true;
+
+    /** Whether the to value is included in the range */
+    boolean toInclusive() default true;
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java
new file mode 100644
index 0000000..1e3c072
--- /dev/null
+++ b/core/java/android/annotation/IntRange.java
@@ -0,0 +1,47 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be an int or long in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  &#64;IntRange(from=0,to=255)
+ *  public int getAlpha() {
+ *      ...
+ *  }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface IntRange {
+    /** Smallest value, inclusive */
+    long from() default Long.MIN_VALUE;
+    /** Largest value, inclusive */
+    long to() default Long.MAX_VALUE;
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/Size.java b/core/java/android/annotation/Size.java
new file mode 100644
index 0000000..389b819
--- /dev/null
+++ b/core/java/android/annotation/Size.java
@@ -0,0 +1,52 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should have a given size or length.
+ * Note that "-1" means "unset". Typically used with a parameter or
+ * return value of type array or collection.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  public void getLocationInWindow(&#64;Size(2) int[] location) {
+ *      ...
+ *  }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD})
+public @interface Size {
+    /** An exact size (or -1 if not specified) */
+    long value() default -1;
+    /** A minimum size, inclusive */
+    long min() default Long.MIN_VALUE;
+    /** A maximum size, inclusive */
+    long max() default Long.MAX_VALUE;
+    /** The size must be a multiple of this factor */
+    long multiple() default 1;
+}
\ No newline at end of file
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a36d34a..9f8befe 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.IntDef;
@@ -921,6 +922,7 @@
      * @see #onRestoreInstanceState
      * @see #onPostCreate
      */
+    @CallSuper
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
         if (mLastNonConfigurationInstances != null) {
@@ -1122,6 +1124,7 @@
      *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
      * @see #onCreate
      */
+    @CallSuper
     protected void onPostCreate(@Nullable Bundle savedInstanceState) {
         if (!isChild()) {
             mTitleReady = true;
@@ -1159,6 +1162,7 @@
      * @see #onStop
      * @see #onResume
      */
+    @CallSuper
     protected void onStart() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
         mCalled = true;
@@ -1196,6 +1200,7 @@
      * @see #onStart
      * @see #onResume
      */
+    @CallSuper
     protected void onRestart() {
         mCalled = true;
     }
@@ -1220,6 +1225,7 @@
      * @see #onPostResume
      * @see #onPause
      */
+    @CallSuper
     protected void onResume() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
         getApplication().dispatchActivityResumed(this);
@@ -1239,6 +1245,7 @@
      *
      * @see #onResume
      */
+    @CallSuper
     protected void onPostResume() {
         final Window win = getWindow();
         if (win != null) win.makeActive();
@@ -1464,6 +1471,7 @@
      * @see #onSaveInstanceState
      * @see #onStop
      */
+    @CallSuper
     protected void onPause() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
         getApplication().dispatchActivityPaused(this);
@@ -1570,6 +1578,7 @@
      * @see #onSaveInstanceState
      * @see #onDestroy
      */
+    @CallSuper
     protected void onStop() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
@@ -1607,6 +1616,7 @@
      * @see #finish
      * @see #isFinishing
      */
+    @CallSuper
     protected void onDestroy() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
         mCalled = true;
@@ -5587,6 +5597,7 @@
      * @see #requestVisibleBehind(boolean)
      * @see #onBackgroundVisibleBehindChanged(boolean)
      */
+    @CallSuper
     public void onVisibleBehindCanceled() {
         mCalled = true;
     }
@@ -5709,6 +5720,7 @@
      *
      * @param mode The new action mode.
      */
+    @CallSuper
     @Override
     public void onActionModeStarted(ActionMode mode) {
     }
@@ -5719,6 +5731,7 @@
      *
      * @param mode The action mode that just finished.
      */
+    @CallSuper
     @Override
     public void onActionModeFinished(ActionMode mode) {
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c6ffef6..c525ef2 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -309,6 +309,21 @@
     /** @hide Process is being cached for later use and is empty. */
     public static final int PROCESS_STATE_CACHED_EMPTY = 13;
 
+    /**
+     * Lock task mode is not active.
+     */
+    public static final int LOCK_TASK_MODE_NONE = 0;
+
+    /**
+     * Full lock task mode is active.
+     */
+    public static final int LOCK_TASK_MODE_LOCKED = 1;
+
+    /**
+     * App pinning mode is active.
+     */
+    public static final int LOCK_TASK_MODE_PINNED = 2;
+
     Point mAppTaskThumbnailSize;
 
     /*package*/ ActivityManager(Context context, Handler handler) {
@@ -2684,12 +2699,25 @@
      * no new tasks can be created or switched to.
      *
      * @see Activity#startLockTask()
+     *
+     * @deprecated Use {@link #getLockTaskModeState} instead.
      */
     public boolean isInLockTaskMode() {
+        return getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+    }
+
+    /**
+     * Return the current state of task locking. The three possible outcomes
+     * are {@link #LOCK_TASK_MODE_NONE}, {@link #LOCK_TASK_MODE_LOCKED}
+     * and {@link #LOCK_TASK_MODE_PINNED}.
+     *
+     * @see Activity#startLockTask()
+     */
+    public int getLockTaskModeState() {
         try {
-            return ActivityManagerNative.getDefault().isInLockTaskMode();
+            return ActivityManagerNative.getDefault().getLockTaskModeState();
         } catch (RemoteException e) {
-            return false;
+            return ActivityManager.LOCK_TASK_MODE_NONE;
         }
     }
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index bb307bb..997f69d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2294,6 +2294,14 @@
             return true;
         }
 
+        case GET_LOCK_TASK_MODE_STATE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final int lockTaskModeState = getLockTaskModeState();
+            reply.writeNoException();
+            reply.writeInt(lockTaskModeState);
+            return true;
+        }
+
         case SET_TASK_DESCRIPTION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -2415,6 +2423,23 @@
             reply.writeNoException();
             return true;
         }
+
+        case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String procName = data.readString();
+            long maxMemSize = data.readLong();
+            setDumpHeapDebugLimit(procName, maxMemSize);
+            reply.writeNoException();
+            return true;
+        }
+
+        case DUMP_HEAP_FINISHED_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String path = data.readString();
+            dumpHeapFinished(path);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -5420,6 +5445,19 @@
     }
 
     @Override
+    public int getLockTaskModeState() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_LOCK_TASK_MODE_STATE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int lockTaskModeState = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return lockTaskModeState;
+    }
+
+    @Override
     public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -5595,5 +5633,30 @@
         reply.recycle();
     }
 
+    @Override
+    public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(processName);
+        data.writeLong(maxMemSize);
+        mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public void dumpHeapFinished(String path) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(path);
+        mRemote.transact(DUMP_HEAP_FINISHED_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 653b951..97793c5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -121,7 +121,6 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.TimeZone;
-import java.util.regex.Pattern;
 
 import libcore.io.DropBox;
 import libcore.io.EventLogger;
@@ -160,7 +159,6 @@
     private static final boolean DEBUG_MEMORY_TRIM = false;
     private static final boolean DEBUG_PROVIDER = false;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
-    private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
     private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
     private static final int LOG_AM_ON_RESUME_CALLED = 30022;
@@ -4247,6 +4245,10 @@
         } else {
             Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
         }
+        try {
+            ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path);
+        } catch (RemoteException e) {
+        }
     }
 
     final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
@@ -4986,7 +4988,7 @@
 
     private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
             ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
-        final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
+        final String auths[] = holder.info.authority.split(";");
         final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
 
         final ProviderClientRecord pcr = new ProviderClientRecord(
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 95870cf..4bd2332 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -206,8 +206,10 @@
     public static final int OP_PROJECT_MEDIA = 46;
     /** @hide Activate a VPN connection without user intervention. */
     public static final int OP_ACTIVATE_VPN = 47;
+    /** @hide Access the WallpaperManagerAPI to write wallpapers. */
+    public static final int OP_WRITE_WALLPAPER = 48;
     /** @hide */
-    public static final int _NUM_OP = 48;
+    public static final int _NUM_OP = 49;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION =
@@ -285,6 +287,7 @@
             OP_TOAST_WINDOW,
             OP_PROJECT_MEDIA,
             OP_ACTIVATE_VPN,
+            OP_WRITE_WALLPAPER,
     };
 
     /**
@@ -340,6 +343,7 @@
             null,
             null,
             OPSTR_ACTIVATE_VPN,
+            null,
     };
 
     /**
@@ -395,6 +399,7 @@
             "TOAST_WINDOW",
             "PROJECT_MEDIA",
             "ACTIVATE_VPN",
+            "WRITE_WALLPAPER",
     };
 
     /**
@@ -450,6 +455,7 @@
             null, // no permission for displaying toasts
             null, // no permission for projecting media
             null, // no permission for activating vpn
+            null, // no permission for supporting wallpaper
     };
 
     /**
@@ -506,6 +512,7 @@
             UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW
             null, //PROJECT_MEDIA
             UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN
+            UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
     };
 
     /**
@@ -561,6 +568,7 @@
             true, //TOAST_WINDOW
             false, //PROJECT_MEDIA
             false, //ACTIVATE_VPN
+            false, //WALLPAPER
     };
 
     /**
@@ -615,6 +623,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
             AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
+            AppOpsManager.MODE_ALLOWED,
     };
 
     /**
@@ -673,6 +682,7 @@
             false,
             false,
             false,
+            false,
     };
 
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index e465d57..8e64b34 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
@@ -1010,6 +1011,7 @@
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeStarted(mode).
      */
+    @CallSuper
     public void onActionModeStarted(ActionMode mode) {
         mActionMode = mode;
     }
@@ -1020,6 +1022,7 @@
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeFinished(mode).
      */
+    @CallSuper
     public void onActionModeFinished(ActionMode mode) {
         if (mode == mActionMode) {
             mActionMode = null;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a7e9413..3dcbdd2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -461,6 +461,8 @@
 
     public boolean isInLockTaskMode() throws RemoteException;
 
+    public int getLockTaskModeState() throws RemoteException;
+
     public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException;
     public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
@@ -480,6 +482,9 @@
     public void systemBackupRestored() throws RemoteException;
     public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
 
+    public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException;
+    public void dumpHeapFinished(String path) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -510,7 +515,7 @@
                 dest.writeStrongBinder(null);
             }
             dest.writeStrongBinder(connection);
-            dest.writeInt(noReleaseNeeded ? 1:0);
+            dest.writeInt(noReleaseNeeded ? 1 : 0);
         }
 
         public static final Parcelable.Creator<ContentProviderHolder> CREATOR
@@ -529,7 +534,7 @@
         private ContentProviderHolder(Parcel source) {
             info = ProviderInfo.CREATOR.createFromParcel(source);
             provider = ContentProviderNative.asInterface(
-                source.readStrongBinder());
+                    source.readStrongBinder());
             connection = source.readStrongBinder();
             noReleaseNeeded = source.readInt() != 0;
         }
@@ -810,4 +815,7 @@
     int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283;
     int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284;
     int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285;
+    int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286;
+    int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287;
+    int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288;
 }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3b5900b..ccba250 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -29,13 +29,18 @@
     /**
      * Set the wallpaper.
      */
-    ParcelFileDescriptor setWallpaper(String name);
+    ParcelFileDescriptor setWallpaper(String name, in String callingPackage);
     
     /**
      * Set the live wallpaper.
      */
+    void setWallpaperComponentChecked(in ComponentName name, in String callingPackage);
+
+    /**
+     * Set the live wallpaper.
+     */
     void setWallpaperComponent(in ComponentName name);
-    
+
     /**
      * Get the wallpaper.
      */
@@ -50,7 +55,7 @@
     /**
      * Clear the wallpaper.
      */
-    void clearWallpaper();
+    void clearWallpaper(in String callingPackage);
 
     /**
      * Return whether there is a wallpaper set with the given name.
@@ -61,7 +66,7 @@
      * Sets the dimension hint for the wallpaper. These hints indicate the desired
      * minimum width and height for the wallpaper.
      */
-    void setDimensionHints(in int width, in int height);
+    void setDimensionHints(in int width, in int height, in String callingPackage);
 
     /**
      * Returns the desired minimum width for the wallpaper.
@@ -76,7 +81,7 @@
     /**
      * Sets extra padding that we would like the wallpaper to have outside of the display.
      */
-    void setDisplayPadding(in Rect padding);
+    void setDisplayPadding(in Rect padding, in String callingPackage);
 
     /**
      * Returns the name of the wallpaper. Private API.
@@ -87,4 +92,9 @@
      * Informs the service that wallpaper settings have been restored. Private API.
      */
     void settingsRestored();
+
+    /**
+     * Check whether wallpapers are supported for the calling user.
+     */
+    boolean isWallpaperSupported(in String callingPackage);
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index ad2b61f..5572d30 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1322,7 +1322,10 @@
     
     /*
      * Starts allocation counting. This triggers a gc and resets the counts.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public void startAllocCounting() {
         // Before we start trigger a GC and reset the debug counts. Run the 
         // finalizers and another GC before starting and stopping the alloc
@@ -1340,7 +1343,10 @@
     
     /*
      * Stops allocation counting.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public void stopAllocCounting() {
         Runtime.getRuntime().gc();
         Runtime.getRuntime().runFinalization();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9c00e1c..85a6aff 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
@@ -338,6 +339,7 @@
      * @see #FLAG_SHOW_LIGHTS
      * @see #flags
      */
+    @ColorInt
     public int ledARGB;
 
     /**
@@ -415,7 +417,6 @@
      * Bit to be bitwise-ored into the {@link #flags} field that should be
      * set if the notification should be canceled when it is clicked by the
      * user.
-
      */
     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
 
@@ -520,12 +521,14 @@
      * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
      * ignored.
      */
+    @ColorInt
     public int color = COLOR_DEFAULT;
 
     /**
      * Special value of {@link #color} telling the system not to decorate this notification with
      * any special color but instead use default colors when presenting this notification.
      */
+    @ColorInt
     public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
 
     /**
@@ -2388,7 +2391,7 @@
          * @see Notification#ledOnMS
          * @see Notification#ledOffMS
          */
-        public Builder setLights(int argb, int onMs, int offMs) {
+        public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
             mLedArgb = argb;
             mLedOnMs = onMs;
             mLedOffMs = offMs;
@@ -2712,7 +2715,7 @@
          *
          * @return The same Builder.
          */
-        public Builder setColor(int argb) {
+        public Builder setColor(@ColorInt int argb) {
             mColor = argb;
             return this;
         }
@@ -5160,7 +5163,7 @@
          * automotive setting. This method can be used to override the color provided in the
          * notification in such a situation.
          */
-        public CarExtender setColor(int color) {
+        public CarExtender setColor(@ColorInt int color) {
             mColor = color;
             return this;
         }
@@ -5170,6 +5173,7 @@
          *
          * @see setColor
          */
+        @ColorInt
         public int getColor() {
             return mColor;
         }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index badb606..22e79b6 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -64,7 +64,10 @@
  * Provides access to the system wallpaper. With WallpaperManager, you can
  * get the current wallpaper, get the desired dimensions for the wallpaper, set
  * the wallpaper, and more. Get an instance of WallpaperManager with
- * {@link #getInstance(android.content.Context) getInstance()}. 
+ * {@link #getInstance(android.content.Context) getInstance()}.
+ *
+ * <p> An app can check whether wallpapers are supported for the current user, by calling
+ * {@link #isWallpaperSupported()}.
  */
 public class WallpaperManager {
     private static String TAG = "WallpaperManager";
@@ -249,6 +252,15 @@
 
         public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
             synchronized (this) {
+                if (mService != null) {
+                    try {
+                        if (!mService.isWallpaperSupported(context.getOpPackageName())) {
+                            return null;
+                        }
+                    } catch (RemoteException e) {
+                        // Ignore
+                    }
+                }
                 if (mWallpaper != null) {
                     return mWallpaper;
                 }
@@ -618,7 +630,9 @@
      * wallpaper will require reloading it again from disk.
      */
     public void forgetLoadedWallpaper() {
-        sGlobals.forgetLoadedWallpaper();
+        if (isWallpaperSupported()) {
+            sGlobals.forgetLoadedWallpaper();
+        }
     }
 
     /**
@@ -717,7 +731,7 @@
             Resources resources = mContext.getResources();
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
-                    "res:" + resources.getResourceName(resid));
+                    "res:" + resources.getResourceName(resid), mContext.getOpPackageName());
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -753,7 +767,8 @@
             return;
         }
         try {
-            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
+            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
+                    mContext.getOpPackageName());
             if (fd == null) {
                 return;
             }
@@ -792,7 +807,8 @@
             return;
         }
         try {
-            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
+            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
+                    mContext.getOpPackageName());
             if (fd == null) {
                 return;
             }
@@ -945,7 +961,8 @@
             if (sGlobals.mService == null) {
                 Log.w(TAG, "WallpaperService not running");
             } else {
-                sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+                sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             // Ignore
@@ -966,7 +983,7 @@
             if (sGlobals.mService == null) {
                 Log.w(TAG, "WallpaperService not running");
             } else {
-                sGlobals.mService.setDisplayPadding(padding);
+                sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             // Ignore
@@ -1006,7 +1023,7 @@
             return;
         }
         try {
-            sGlobals.mService.clearWallpaper();
+            sGlobals.mService.clearWallpaper(mContext.getOpPackageName());
         } catch (RemoteException e) {
             // Ignore
         }
@@ -1027,7 +1044,7 @@
             return false;
         }
         try {
-            sGlobals.mService.setWallpaperComponent(name);
+            sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
             return true;
         } catch (RemoteException e) {
             // Ignore
@@ -1096,7 +1113,24 @@
             // Ignore.
         }
     }
-    
+
+    /**
+     * Returns whether wallpapers are supported for the calling user. If this function returns
+     * false, any attempts to changing the wallpaper will have no effect.
+     */
+    public boolean isWallpaperSupported() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+        } else {
+            try {
+                return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        }
+        return false;
+    }
+
     /**
      * Clear the offsets previously associated with this window through
      * {@link #setWallpaperOffsets(IBinder, float, float)}.  This reverts
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 4fc990e..fe284ce 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -168,8 +168,8 @@
 
     /**
      * Action sent to a device administrator to notify that the device is entering
-     * lock task mode from an authorized package.  The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
-     * will describe the authorized package using lock task mode.
+     * lock task mode.  The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
+     * will describe the package using lock task mode.
      *
      * <p>The calling device admin must be the device owner or profile
      * owner to receive this broadcast.
@@ -182,7 +182,7 @@
 
     /**
      * Action sent to a device administrator to notify that the device is exiting
-     * lock task mode from an authorized package.
+     * lock task mode.
      *
      * <p>The calling device admin must be the device owner or profile
      * owner to receive this broadcast.
@@ -215,7 +215,8 @@
      * <p>A device admin application which listens to this intent can find out if the device was
      * provisioned for the device owner or profile owner case by calling respectively
      * {@link android.app.admin.DevicePolicyManager#isDeviceOwnerApp} and
-     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}.
+     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}. You will generally handle
+     * this in {@link DeviceAdminReceiver#onProfileProvisioningComplete}.
      *
      * <p>Input: Nothing.</p>
      * <p>Output: Nothing</p>
@@ -224,6 +225,23 @@
     public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
             "android.app.action.PROFILE_PROVISIONING_COMPLETE";
 
+    /**
+     * Broadcast Action: This broadcast is sent to indicate that the system is ready for the device
+     * initializer to perform user setup tasks. This is only applicable to devices managed by a
+     * device owner app.
+     *
+     * <p>The broadcast will be limited to the {@link DeviceAdminReceiver} component specified in
+     * the (@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME) field
+     * of the original intent or NFC bump that started the provisioning process. You will generally
+     * handle this in {@link DeviceAdminReceiver#onReadyForUserInitialization}.
+     *
+     * <p>Input: Nothing.</p>
+     * <p>Output: Nothing</p>
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_READY_FOR_USER_INITIALIZATION =
+            "android.app.action.READY_FOR_USER_INITIALIZATION";
+
     /** @hide */
     public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
 
@@ -245,7 +263,7 @@
     /** @hide */
     public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE";
 
-   /**
+    /**
      * Name under which a DevicePolicy component publishes information
      * about itself.  This meta-data must reference an XML resource containing
      * a device-admin tag.
@@ -382,20 +400,20 @@
     /**
      * Called when provisioning of a managed profile or managed device has completed successfully.
      *
-     * <p> As a prerequisit for the execution of this callback the (@link DeviceAdminReceiver} has
+     * <p> As a prerequisite for the execution of this callback the {@link DeviceAdminReceiver} has
      * to declare an intent filter for {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
      * Its component must also be specified in the {@link DevicePolicyManager#EXTRA_DEVICE_ADMIN}
      * of the {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} intent that started the
      * managed provisioning.
      *
-     * <p>When provisioning is complete, the managed profile is hidden until the profile owner
-     * calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}. Typically a profile
-     * owner will enable the profile when it has finished any additional setup such as adding an
-     * account by using the {@link AccountManager} and calling apis to bring the profile into the
-     * desired state.
+     * <p>When provisioning of a managed profile is complete, the managed profile is hidden until
+     * the profile owner calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}.
+     * Typically a profile owner will enable the profile when it has finished any additional setup
+     * such as adding an account by using the {@link AccountManager} and calling apis to bring the
+     * profile into the desired state.
      *
      * <p> Note that provisioning completes without waiting for any server interactions, so the
-     * profile owner needs to wait for data to be available if required (e.g android device ids or
+     * profile owner needs to wait for data to be available if required (e.g. android device ids or
      * other data that is set as a result of server interactions).
      *
      * @param context The running context as per {@link #onReceive}.
@@ -405,8 +423,31 @@
     }
 
     /**
-     * Called when a device is entering lock task mode by a package authorized
-     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+     * Called during provisioning of a managed device to allow the device initializer to perform
+     * user setup steps. Only device initializers should override this method.
+     *
+     * <p> Called when the DeviceAdminReceiver receives a
+     * {@link #ACTION_READY_FOR_USER_INITIALIZATION} broadcast. As a prerequisite for the execution
+     * of this callback the {@link DeviceAdminReceiver} has
+     * to declare an intent filter for {@link #ACTION_READY_FOR_USER_INITIALIZATION}. Only the
+     * component specified in the
+     * {@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME} field of the
+     * original intent or NFC bump that started the provisioning process will receive this callback.
+     *
+     * <p>It is not assumed that the device initializer is finished when it returns from
+     * this call, as it may do additional setup asynchronously. The device initializer must call
+     * {DevicePolicyManager#setUserEnabled(ComponentName admin)} when it has finished any additional
+     * setup (such as adding an account by using the {@link AccountManager}) in order for the user
+     * to be functional.
+     *
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onReadyForUserInitialization(Context context, Intent intent) {
+    }
+
+    /**
+     * Called when a device is entering lock task mode.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
@@ -416,8 +457,7 @@
     }
 
     /**
-     * Called when a device is exiting lock task mode by a package authorized
-     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+     * Called when a device is exiting lock task mode.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
@@ -488,6 +528,8 @@
             onLockTaskModeEntering(context, intent, pkg);
         } else if (ACTION_LOCK_TASK_EXITING.equals(action)) {
             onLockTaskModeExiting(context, intent);
+        } else if (ACTION_READY_FOR_USER_INITIALIZATION.equals(action)) {
+            onReadyForUserInitialization(context, intent);
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 170224d..e23ffe4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -28,6 +28,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
 import android.net.ProxyInfo;
 import android.os.Bundle;
 import android.os.Handler;
@@ -108,7 +109,11 @@
      * Provisioning adds a managed profile and sets the MDM as the profile owner who has full
      * control over the profile.
      *
-     * <p>This intent must contain the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+     * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this intent must contain the
+     * extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+     * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain the extra
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported.
      *
      * <p> When managed provisioning has completed, broadcasts are sent to the application specified
      * in the provisioning intent. The
@@ -149,11 +154,36 @@
      *
      * <p>This package is set as device owner when device owner provisioning is started by an NFC
      * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
+     *
+     * <p> When this extra is set, the application must have exactly one device admin receiver.
+     * This receiver will be set as the profile or device owner and active admin.</p>
+
+     * @see DeviceAdminReceiver
+     * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
+     * supported.
      */
+    @Deprecated
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
 
     /**
+     * A ComponentName extra indicating the device admin receiver of the mobile device management
+     * application that will be set as the profile owner or device owner and active admin.
+     *
+     * <p>If an application starts provisioning directly via an intent with action
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE} the package name of this component has to match the
+     * package name of the application that started provisioning.
+     *
+     * <p>This component is set as device owner and active admin when device owner provisioning is
+     * started by an NFC message containing an NFC record with MIME type
+     * {@link #MIME_TYPE_PROVISIONING_NFC}.
+     *
+     * @see DeviceAdminReceiver
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME
+        = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
+
+    /**
      * An {@link android.accounts.Account} extra holding the account to migrate during managed
      * profile provisioning. If the account supplied is present in the primary user, it will be
      * copied, along with its credentials to the managed profile and removed from the primary user.
@@ -357,6 +387,52 @@
              "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
 
     /**
+     * On devices managed by a device owner app, a String representation of a Component name extra
+     * indicating the component of the application that is temporarily granted device owner
+     * privileges during device initialization and profile owner privileges during secondary user
+     * initialization.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     * @see ComponentName#unflattenFromString()
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+
+    /**
+     * A String extra holding an http url that specifies the download location of the device
+     * initializer package. When not provided it is assumed that the device initializer package is
+     * already installed.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
+
+    /**
+     * A String extra holding a http cookie header which should be used in the http request to the
+     * url specified in {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+
+    /**
+     * A String extra holding the SHA-1 checksum of the file at download location specified in
+     * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't
+     * match the file at the download location an error will be shown to the user and the user will
+     * be asked to factory reset the device.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
+
+    /**
      * This MIME type is used for starting the Device Owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -372,7 +448,6 @@
      * <p>The NFC record must contain a serialized {@link java.util.Properties} object which
      * contains the following properties:
      * <ul>
-     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}</li>
@@ -389,6 +464,15 @@
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li></ul>
      *
+     * <p>
+     * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, it should also contain
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+     * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, (although
+     * specifying only {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported).
+     * This componentName must have been converted to a String via
+     * {@link android.content.ComponentName#flattenToString()}
+     *
      * <p> When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
      * device owner.
@@ -2382,6 +2466,113 @@
     }
 
     /**
+     * Sets the given component as the device initializer. The package must already be installed and
+     * set as an active device administrator, and there must not be an existing device initializer,
+     * for this call to succeed. This method can only be called by an app holding the
+     * MANAGE_DEVICE_ADMINS permission before the device is provisioned or by a device owner app. A
+     * device initializer app is granted device owner privileges during device initialization and
+     * profile owner privileges during secondary user initialization.
+     * @param who Which {@link DeviceAdminReceiver} this request is associated with, or null if not
+     *        called by the device owner.
+     * @param initializer Which {@link DeviceAdminReceiver} to make device initializer.
+     * @param initializerName The user-visible name of the device initializer.
+     * @return whether the package was successfully registered as the device initializer.
+     * @throws IllegalArgumentException if the package name is null or invalid
+     * @throws IllegalStateException if the caller is not device owner or the device has
+     *         already been provisioned or a device initializer already exists.
+     */
+    public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
+            String initializerName) throws IllegalArgumentException, IllegalStateException {
+        if (mService != null) {
+            try {
+                return mService.setDeviceInitializer(who, initializer, initializerName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to set device initializer");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Used to determine if a particular package has been registered as the device initializer.
+     *
+     * @param packageName the package name of the app, to compare with the registered device
+     *        initializer app, if any.
+     * @return whether or not the caller is registered as the device initializer app.
+     */
+    public boolean isDeviceInitializerApp(String packageName) {
+        if (mService != null) {
+            try {
+                return mService.isDeviceInitializer(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to check device initializer");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the device initializer, so that it will not be invoked on user initialization for any
+     * subsequently created users. This method can be called by either the device owner or device
+     * initializer itself. The caller must be an active administrator.
+     *
+     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public void clearDeviceInitializerApp(ComponentName who) {
+        if (mService != null) {
+            try {
+                mService.clearDeviceInitializer(who);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to clear device initializer");
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Gets the device initializer of the system.
+     *
+     * @return the package name of the device initializer.
+     */
+    @SystemApi
+    public String getDeviceInitializerApp() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceInitializer();
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get device initializer");
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets the enabled state of the user. A user should be enabled only once it is ready to
+     * be used.
+     *
+     * <p>Device initializer must call this method to mark the user as functional.
+     * Only the device initializer agent can call this.
+     *
+     * <p>When the user is enabled, if the device initializer is not also the device owner, the
+     * device initializer will no longer have elevated permissions to call methods in this class.
+     * Additionally, it will be removed as an active administrator and its
+     * {@link DeviceAdminReceiver} will be disabled.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return whether the user is now enabled.
+     */
+    public boolean setUserEnabled(ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.setUserEnabled(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * @hide
      * @deprecated Use #ACTION_SET_PROFILE_OWNER
      * Sets the given component as an active admin and registers the package as the profile
@@ -2709,7 +2900,6 @@
      * <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
      * then it's up to the TrustAgent itself to aggregate the values from all device admins.
      * <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
-     * @hide
      */
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
             PersistableBundle configuration) {
@@ -2735,7 +2925,6 @@
      * for this {@param agent} or calls it with a null configuration, null is returned.
      * @param agent Which component to get enabled features for.
      * @return configuration for the given trust agent.
-     * @hide
      */
     public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
             ComponentName agent) {
@@ -3119,8 +3308,7 @@
     }
 
     /**
-     * Called by a profile or device owner to set a user restriction specified
-     * by the key.
+     * Called by a profile or device owner to set a user restriction specified by the key.
      * <p>
      * The calling device admin must be a profile or device owner; if it is not,
      * a security exception will be thrown.
@@ -3141,8 +3329,7 @@
     }
 
     /**
-     * Called by a profile or device owner to clear a user restriction specified
-     * by the key.
+     * Called by a profile or device owner to clear a user restriction specified by the key.
      * <p>
      * The calling device admin must be a profile or device owner; if it is not,
      * a security exception will be thrown.
@@ -3163,7 +3350,7 @@
     }
 
     /**
-     * Called by device or profile owner to hide or unhide packages. When a package is hidden it
+     * Called by profile or device owners to hide or unhide packages. When a package is hidden it
      * is unavailable for use, but the data and actual package file remain.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3185,7 +3372,7 @@
     }
 
     /**
-     * Called by device or profile owner to determine if a package is hidden.
+     * Called by profile or device owners to determine if a package is hidden.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package to retrieve the hidden status of.
@@ -3203,7 +3390,7 @@
     }
 
     /**
-     * Called by profile or device owner to re-enable a system app that was disabled by default
+     * Called by profile or device owners to re-enable a system app that was disabled by default
      * when the user was initialized.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3220,7 +3407,7 @@
     }
 
     /**
-     * Called by profile or device owner to re-enable system apps by intent that were disabled
+     * Called by profile or device owners to re-enable system apps by intent that were disabled
      * by default when the user was initialized.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3494,9 +3681,14 @@
     /**
      * Check whether the current user has been blocked by device policy from uninstalling a package.
      * Requires the caller to be the profile owner if checking a specific admin's policy.
+     * <p>
+     * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the
+     * behavior of this API is changed such that passing <code>null</code> as the <code>admin</code>
+     * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing
+     * <code>null</code> will cause a NullPointerException to be raised.
      *
      * @param admin The name of the admin component whose blocking policy will be checked, or null
-     *        to check if any admin has blocked the uninstallation.
+     *            to check if any admin has blocked the uninstallation.
      * @param packageName package to check.
      * @return true if uninstallation is blocked.
      */
@@ -3591,4 +3783,18 @@
         }
         return Collections.emptyList();
     }
+
+    /**
+     * Called by profile or device owners to set the current user's photo.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param icon the bitmap to set as the photo.
+     */
+    public void setUserIcon(ComponentName admin, Bitmap icon) {
+        try {
+            mService.setUserIcon(admin, icon);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set the user icon ", re);
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 714e740..f69cf36 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Bitmap;
 import android.net.ProxyInfo;
 import android.os.Bundle;
 import android.os.PersistableBundle;
@@ -199,4 +200,12 @@
     boolean getAutoTimeRequired();
 
     boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
+
+    boolean setUserEnabled(in ComponentName who);
+    boolean isDeviceInitializer(String packageName);
+    void clearDeviceInitializer(in ComponentName who);
+    boolean setDeviceInitializer(in ComponentName who, in ComponentName initializer, String initializerName);
+    String getDeviceInitializer();
+
+    void setUserIcon(in ComponentName admin, in Bitmap icon);
 }
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 1b1e600..7f89100 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -258,6 +258,7 @@
      *
      * <ul>
      * <li>The contents of the {@link #getCacheDir()} directory</li>
+     * <li>The contents of the {@link #getCodeCacheDir()} directory</li>
      * <li>The contents of the {@link #getNoBackupFilesDir()} directory</li>
      * <li>The contents of the app's shared library directory</li>
      * </ul>
@@ -285,6 +286,7 @@
         String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
         String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
         String cacheDir = getCacheDir().getCanonicalPath();
+        String codeCacheDir = getCodeCacheDir().getCanonicalPath();
         String libDir = (appInfo.nativeLibraryDir != null)
                 ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
                 : null;
@@ -298,6 +300,7 @@
             filterSet.add(libDir);
         }
         filterSet.add(cacheDir);
+        filterSet.add(codeCacheDir);
         filterSet.add(databaseDir);
         filterSet.add(sharedPrefsDir);
         filterSet.add(filesDir);
@@ -354,6 +357,7 @@
         String dbDir;
         String spDir;
         String cacheDir;
+        String codeCacheDir;
         String libDir;
         String efDir = null;
         String filePath;
@@ -367,6 +371,7 @@
             dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
             spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
             cacheDir = getCacheDir().getCanonicalPath();
+            codeCacheDir = getCodeCacheDir().getCanonicalPath();
             libDir = (appInfo.nativeLibraryDir == null)
                     ? null
                     : new File(appInfo.nativeLibraryDir).getCanonicalPath();
@@ -380,7 +385,8 @@
             }
 
             // Now figure out which well-defined tree the file is placed in, working from
-            // most to least specific.  We also specifically exclude the lib and cache dirs.
+            // most to least specific.  We also specifically exclude the lib, cache,
+            // and code_cache dirs.
             filePath = file.getCanonicalPath();
         } catch (IOException e) {
             Log.w(TAG, "Unable to obtain canonical paths");
@@ -388,9 +394,10 @@
         }
 
         if (filePath.startsWith(cacheDir)
+                || filePath.startsWith(codeCacheDir)
                 || filePath.startsWith(libDir)
                 || filePath.startsWith(nbFilesDir)) {
-            Log.w(TAG, "lib, cache, and no_backup files are not backed up");
+            Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
             return;
         }
 
diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
index ce87329..161c339 100644
--- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
+++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
@@ -26,32 +26,32 @@
  * @hide
  */
 public final class BluetoothActivityEnergyInfo implements Parcelable {
+    private final long mTimestamp;
     private final int mBluetoothStackState;
     private final int mControllerTxTimeMs;
     private final int mControllerRxTimeMs;
     private final int mControllerIdleTimeMs;
     private final int mControllerEnergyUsed;
-    private final long timestamp;
 
     public static final int BT_STACK_STATE_INVALID = 0;
     public static final int BT_STACK_STATE_STATE_ACTIVE = 1;
     public static final int BT_STACK_STATE_STATE_SCANNING = 2;
     public static final int BT_STACK_STATE_STATE_IDLE = 3;
 
-    public BluetoothActivityEnergyInfo(int stackState, int txTime, int rxTime,
-            int idleTime, int energyUsed) {
+    public BluetoothActivityEnergyInfo(long timestamp, int stackState,
+                                       int txTime, int rxTime, int idleTime, int energyUsed) {
+        mTimestamp = timestamp;
         mBluetoothStackState = stackState;
         mControllerTxTimeMs = txTime;
         mControllerRxTimeMs = rxTime;
         mControllerIdleTimeMs = idleTime;
         mControllerEnergyUsed = energyUsed;
-        timestamp = System.currentTimeMillis();
     }
 
     @Override
     public String toString() {
         return "BluetoothActivityEnergyInfo{"
-            + " timestamp=" + timestamp
+            + " mTimestamp=" + mTimestamp
             + " mBluetoothStackState=" + mBluetoothStackState
             + " mControllerTxTimeMs=" + mControllerTxTimeMs
             + " mControllerRxTimeMs=" + mControllerRxTimeMs
@@ -63,13 +63,14 @@
     public static final Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
             new Parcelable.Creator<BluetoothActivityEnergyInfo>() {
         public BluetoothActivityEnergyInfo createFromParcel(Parcel in) {
+            long timestamp = in.readLong();
             int stackState = in.readInt();
             int txTime = in.readInt();
             int rxTime = in.readInt();
             int idleTime = in.readInt();
             int energyUsed = in.readInt();
-            return new BluetoothActivityEnergyInfo(stackState, txTime, rxTime,
-                    idleTime, energyUsed);
+            return new BluetoothActivityEnergyInfo(timestamp, stackState,
+                    txTime, rxTime, idleTime, energyUsed);
         }
         public BluetoothActivityEnergyInfo[] newArray(int size) {
             return new BluetoothActivityEnergyInfo[size];
@@ -77,6 +78,7 @@
     };
 
     public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mTimestamp);
         out.writeInt(mBluetoothStackState);
         out.writeInt(mControllerTxTimeMs);
         out.writeInt(mControllerRxTimeMs);
@@ -123,11 +125,12 @@
     public int getControllerEnergyUsed() {
         return mControllerEnergyUsed;
     }
+
     /**
-     * @return timestamp(wall clock) of record creation
+     * @return timestamp(real time elapsed in milliseconds since boot) of record creation.
      */
     public long getTimeStamp() {
-        return timestamp;
+        return mTimestamp;
     }
 
     /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 010c860..61cdec3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.CheckResult;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -3041,6 +3042,7 @@
      * @see PackageManager#checkPermission(String, String)
      * @see #checkCallingPermission
      */
+    @CheckResult(suggest="#enforcePermission(String,int,int,String)")
     @PackageManager.PermissionResult
     public abstract int checkPermission(@NonNull String permission, int pid, int uid);
 
@@ -3070,6 +3072,7 @@
      * @see #checkPermission
      * @see #checkCallingOrSelfPermission
      */
+    @CheckResult(suggest="#enforceCallingPermission(String,String)")
     @PackageManager.PermissionResult
     public abstract int checkCallingPermission(@NonNull String permission);
 
@@ -3089,6 +3092,7 @@
      * @see #checkPermission
      * @see #checkCallingPermission
      */
+    @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)")
     @PackageManager.PermissionResult
     public abstract int checkCallingOrSelfPermission(@NonNull String permission);
 
@@ -3233,6 +3237,7 @@
      *
      * @see #checkCallingUriPermission
      */
+    @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)")
     public abstract int checkUriPermission(Uri uri, int pid, int uid,
             @Intent.AccessUriMode int modeFlags);
 
@@ -3261,6 +3266,7 @@
      *
      * @see #checkUriPermission(Uri, int, int, int)
      */
+    @CheckResult(suggest="#enforceCallingUriPermission(Uri,int,String)")
     public abstract int checkCallingUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags);
 
     /**
@@ -3280,6 +3286,7 @@
      *
      * @see #checkCallingUriPermission
      */
+    @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)")
     public abstract int checkCallingOrSelfUriPermission(Uri uri,
             @Intent.AccessUriMode int modeFlags);
 
@@ -3305,6 +3312,7 @@
      * is allowed to access that uri or holds one of the given permissions, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      */
+    @CheckResult(suggest="#enforceUriPermission(Uri,String,String,int,int,int,String)")
     public abstract int checkUriPermission(@Nullable Uri uri, @Nullable String readPermission,
             @Nullable String writePermission, int pid, int uid,
             @Intent.AccessUriMode int modeFlags);
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 8487dae..71a035e 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -20,7 +20,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
 Utility class to aid in matching URIs in content providers.
@@ -171,7 +170,7 @@
             if (path.length() > 0 && path.charAt(0) == '/') {
                 newPath = path.substring(1);
             }
-            tokens = PATH_SPLIT_PATTERN.split(newPath);
+            tokens = newPath.split("/");
         }
 
         int numTokens = tokens != null ? tokens.length : 0;
@@ -207,8 +206,6 @@
         node.mCode = code;
     }
 
-    static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/");
-
     /**
      * Try to match against the path in a url.
      *
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ebc8e1e..0365689 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.CheckResult;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -2121,6 +2122,7 @@
      * @see #PERMISSION_GRANTED
      * @see #PERMISSION_DENIED
      */
+    @CheckResult
     public abstract int checkPermission(String permName, String pkgName);
 
     /**
@@ -2248,6 +2250,7 @@
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
+    @CheckResult
     public abstract int checkSignatures(String pkg1, String pkg2);
 
     /**
@@ -2270,6 +2273,7 @@
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
+    @CheckResult
     public abstract int checkSignatures(int uid1, int uid2);
 
     /**
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index ace402a..841b09d 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -16,6 +16,7 @@
 
 package android.content.res;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.Resources.Theme;
@@ -91,7 +92,7 @@
      * Creates a ColorStateList that returns the specified mapping from
      * states to colors.
      */
-    public ColorStateList(int[][] states, int[] colors) {
+    public ColorStateList(int[][] states, @ColorInt int[] colors) {
         mStateSpecs = states;
         mColors = colors;
 
@@ -102,7 +103,7 @@
      * @return A ColorStateList containing a single color.
      */
     @NonNull
-    public static ColorStateList valueOf(int color) {
+    public static ColorStateList valueOf(@ColorInt int color) {
         synchronized (sCache) {
             final int index = sCache.indexOfKey(color);
             if (index >= 0) {
@@ -436,6 +437,7 @@
      *
      * @return the default color in this {@link ColorStateList}.
      */
+    @ColorInt
     public int getDefaultColor() {
         return mDefaultColor;
     }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 584f3f6..5dc9ef9 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,6 +16,7 @@
 
 package android.content.res;
 
+import android.annotation.ColorInt;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -925,6 +926,7 @@
      * @return A single color value in the form 0xAARRGGBB.
      * @deprecated Use {@link #getColor(int, Theme)} instead.
      */
+    @ColorInt
     public int getColor(@ColorRes int id) throws NotFoundException {
         return getColor(id, null);
     }
@@ -945,6 +947,7 @@
      *
      * @return A single color value in the form 0xAARRGGBB.
      */
+    @ColorInt
     public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 3e07f0c..1fca920 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -17,6 +17,7 @@
 package android.content.res;
 
 import android.annotation.AnyRes;
+import android.annotation.ColorInt;
 import android.annotation.Nullable;
 import android.graphics.drawable.Drawable;
 import android.os.StrictMode;
@@ -420,7 +421,8 @@
      * @throws UnsupportedOperationException if the attribute is defined but is
      *         not an integer color or color state list.
      */
-    public int getColor(int index, int defValue) {
+    @ColorInt
+    public int getColor(int index, @ColorInt int defValue) {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
@@ -442,8 +444,10 @@
             }
             return defValue;
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index);
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to color: type=0x"
@@ -478,7 +482,7 @@
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
-                        "Failed to resolve attribute at index " + index);
+                        "Failed to resolve attribute at index " + index + ": " + value);
             }
             return mResources.loadColorStateList(value, value.resourceId, mTheme);
         }
@@ -514,8 +518,10 @@
                 && type <= TypedValue.TYPE_LAST_INT) {
             return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index);
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to integer: type=0x"
@@ -558,8 +564,10 @@
             return TypedValue.complexToDimension(
                     data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index);
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -603,8 +611,10 @@
             return TypedValue.complexToDimensionPixelOffset(
                     data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index);
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -649,8 +659,10 @@
             return TypedValue.complexToDimensionPixelSize(
                 data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index);
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -690,8 +702,10 @@
             return TypedValue.complexToDimensionPixelSize(
                 data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index);
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException(getPositionDescription()
@@ -763,8 +777,10 @@
             return TypedValue.complexToFraction(
                 data[index+AssetManager.STYLE_DATA], base, pbase);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
             throw new UnsupportedOperationException(
-                    "Failed to resolve attribute at index " + index);
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
@@ -851,7 +867,7 @@
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
-                        "Failed to resolve attribute at index " + index);
+                        "Failed to resolve attribute at index " + index + ": " + value);
             }
             return mResources.loadDrawable(value, value.resourceId, mTheme);
         }
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index e1a2a25..e0d454c 100644
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -16,6 +16,7 @@
 
 package android.gesture;
 
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -204,18 +205,20 @@
         mOrientation = orientation;
     }
 
-    public void setGestureColor(int color) {
+    public void setGestureColor(@ColorInt int color) {
         mCertainGestureColor = color;
     }
 
-    public void setUncertainGestureColor(int color) {
+    public void setUncertainGestureColor(@ColorInt int color) {
         mUncertainGestureColor = color;
     }
 
+    @ColorInt
     public int getUncertainGestureColor() {
         return mUncertainGestureColor;
     }
 
+    @ColorInt
     public int getGestureColor() {
         return mCertainGestureColor;
     }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 87ec06a..a0217c2 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2493,6 +2493,83 @@
     public static final Key<Integer> SYNC_MAX_LATENCY =
             new Key<Integer>("android.sync.maxLatency", int.class);
 
+    /**
+     * <p>The available depth dataspace stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     * <p>These are output stream configurations for use with
+     * dataSpace HAL_DATASPACE_DEPTH. The configurations are
+     * listed as <code>(format, width, height, input?)</code> tuples.</p>
+     * <p>Only devices that support depth output for at least
+     * the HAL_PIXEL_FORMAT_Y16 dense depth map may include
+     * this entry.</p>
+     * <p>A device that also supports the HAL_PIXEL_FORMAT_BLOB
+     * sparse depth point cloud must report a single entry for
+     * the format in this list as <code>(HAL_PIXEL_FORMAT_BLOB,
+     * android.depth.maxDepthSamples, 1, OUTPUT)</code> in addition to
+     * the entries for HAL_PIXEL_FORMAT_Y16.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfiguration[]> DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.depth.availableDepthStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
+
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for depth output formats.</p>
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>The minimum frame duration of a stream (of a particular format, size)
+     * is the same regardless of whether the stream is input or output.</p>
+     * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
+     * android.scaler.availableStallDurations for more details about
+     * calculating the max frame rate.</p>
+     * <p>(Keep in sync with
+     * StreamConfigurationMap#getOutputMinFrameDuration)</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+    /**
+     * <p>This lists the maximum stall duration for each
+     * format/size combination for depth streams.</p>
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>This functions similarly to
+     * android.scaler.availableStallDurations for depth
+     * streams.</p>
+     * <p>All depth output stream formats may have a nonzero stall
+     * duration.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 50a58ed..d286d38 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -66,7 +66,7 @@
     int deleteStream(int streamId);
 
     // non-negative value is the stream ID. negative value is status_t
-    int createStream(int width, int height, int format, in Surface surface);
+    int createStream(in Surface surface);
 
     int createDefaultRequest(int templateId, out CameraMetadataNative request);
 
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index ec450bd1..78aefa5 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -373,9 +373,7 @@
 
                 // Add all new streams
                 for (Surface s : addSet) {
-                    // TODO: remove width,height,format since we are ignoring
-                    // it.
-                    int streamId = mRemoteDevice.createStream(0, 0, 0, s);
+                    int streamId = mRemoteDevice.createStream(s);
                     mConfiguredOutputs.put(streamId, s);
                 }
 
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index fcf172c..26cd498 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -504,7 +504,7 @@
     }
 
     @Override
-    public int createStream(int width, int height, int format, Surface surface) {
+    public int createStream(Surface surface) {
         if (DEBUG) {
             Log.d(TAG, "createStream called.");
         }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 43d3a71..d96a0e9 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -86,10 +86,10 @@
      */
     public static final int WIFI_SCAN = 6;
 
-     /**
-      * A constant indicating a wifi multicast timer
-      */
-     public static final int WIFI_MULTICAST_ENABLED = 7;
+    /**
+     * A constant indicating a wifi multicast timer
+     */
+    public static final int WIFI_MULTICAST_ENABLED = 7;
 
     /**
      * A constant indicating a video turn on timer
@@ -353,7 +353,9 @@
         public abstract long getWifiRunningTime(long elapsedRealtimeUs, int which);
         public abstract long getFullWifiLockTime(long elapsedRealtimeUs, int which);
         public abstract long getWifiScanTime(long elapsedRealtimeUs, int which);
+        public abstract int getWifiScanCount(int which);
         public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which);
+        public abstract int getWifiBatchedScanCount(int csphBin, int which);
         public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which);
         public abstract long getAudioTurnedOnTime(long elapsedRealtimeUs, int which);
         public abstract long getVideoTurnedOnTime(long elapsedRealtimeUs, int which);
@@ -439,14 +441,14 @@
             public abstract boolean isActive();
 
             /**
-             * Returns the total time (in 1/100 sec) spent executing in user code.
+             * Returns the total time (in milliseconds) spent executing in user code.
              *
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
             public abstract long getUserTime(int which);
 
             /**
-             * Returns the total time (in 1/100 sec) spent executing in system code.
+             * Returns the total time (in milliseconds) spent executing in system code.
              *
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
@@ -474,14 +476,14 @@
             public abstract int getNumAnrs(int which);
 
             /**
-             * Returns the cpu time spent in microseconds while the process was in the foreground.
+             * Returns the cpu time (milliseconds) spent while the process was in the foreground.
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              * @return foreground cpu time in microseconds
              */
             public abstract long getForegroundTime(int which);
 
             /**
-             * Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
+             * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed.
              * @param speedStep the index of the CPU speed. This is not the actual speed of the
              * CPU.
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
@@ -635,24 +637,34 @@
             while (i < N && (c=value.charAt(i)) != '-') {
                 i++;
                 switch (c) {
-                    case 'f': out |= ((Display.STATE_OFF-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
-                    case 'o': out |= ((Display.STATE_ON-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
-                    case 'd': out |= ((Display.STATE_DOZE-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
-                    case 'z': out |= ((Display.STATE_DOZE_SUSPEND-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+                    case 'f': out |= (((long)Display.STATE_OFF-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
                         break;
-                    case 'p': out |= (STEP_LEVEL_MODE_POWER_SAVE<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+                    case 'o': out |= (((long)Display.STATE_ON-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
                         break;
-                    case 'F': out |= ((Display.STATE_OFF-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
-                    case 'O': out |= ((Display.STATE_ON-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
-                    case 'D': out |= ((Display.STATE_DOZE-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
-                    case 'Z': out |= ((Display.STATE_DOZE_SUSPEND-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                    case 'd': out |= (((long)Display.STATE_DOZE-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
                         break;
-                    case 'P': out |= (STEP_LEVEL_MODE_POWER_SAVE<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                    case 'z': out |= (((long)Display.STATE_DOZE_SUSPEND-1)
+                            << STEP_LEVEL_INITIAL_MODE_SHIFT);
+                        break;
+                    case 'p': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
+                            << STEP_LEVEL_INITIAL_MODE_SHIFT);
+                        break;
+                    case 'F': out |= (((long)Display.STATE_OFF-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'O': out |= (((long)Display.STATE_ON-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'D': out |= (((long)Display.STATE_DOZE-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'Z': out |= (((long)Display.STATE_DOZE_SUSPEND-1)
+                            << STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'P': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
+                            << STEP_LEVEL_MODIFIED_MODE_SHIFT);
                         break;
                 }
             }
             i++;
-            int level = 0;
+            long level = 0;
             while (i < N && (c=value.charAt(i)) != '-') {
                 i++;
                 level <<= 4;
@@ -664,6 +676,7 @@
                     level += c - 'A' + 10;
                 }
             }
+            i++;
             out |= (level << STEP_LEVEL_LEVEL_SHIFT) & STEP_LEVEL_LEVEL_MASK;
             long duration = 0;
             while (i < N && (c=value.charAt(i)) != '-') {
@@ -1845,6 +1858,15 @@
     public abstract long getNetworkActivityBytes(int type, int which);
     public abstract long getNetworkActivityPackets(int type, int which);
 
+    public static final int CONTROLLER_IDLE_TIME = 0;
+    public static final int CONTROLLER_RX_TIME = 1;
+    public static final int CONTROLLER_TX_TIME = 2;
+    public static final int CONTROLLER_ENERGY = 3;
+    public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_ENERGY + 1;
+
+    public abstract long getBluetoothControllerActivity(int type, int which);
+    public abstract long getWifiControllerActivity(int type, int which);
+
     /**
      * Return the wall clock time when battery stats data collection started.
      */
@@ -2129,13 +2151,6 @@
         }
     }
 
-    public final static void formatTime(StringBuilder sb, long time) {
-        long sec = time / 100;
-        formatTimeRaw(sb, sec);
-        sb.append((time - (sec * 100)) * 10);
-        sb.append("ms ");
-    }
-
     public final static void formatTimeMs(StringBuilder sb, long time) {
         long sec = time / 1000;
         formatTimeRaw(sb, sec);
@@ -2561,6 +2576,7 @@
             long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
             long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            int wifiScanCount = u.getWifiScanCount(which);
             long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
@@ -2573,10 +2589,10 @@
                         mobileActiveTime, mobileActiveCount);
             }
 
-            if (fullWifiLockOnTime != 0 || wifiScanTime != 0
+            if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
                     || uidWifiRunningTime != 0) {
                 dumpLine(pw, uid, category, WIFI_DATA,
-                        fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime);
+                        fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime, wifiScanCount);
             }
 
             if (u.hasUserActivity()) {
@@ -2694,9 +2710,9 @@
                         : processStats.entrySet()) {
                     Uid.Proc ps = ent.getValue();
 
-                    final long userMillis = ps.getUserTime(which) * 10;
-                    final long systemMillis = ps.getSystemTime(which) * 10;
-                    final long foregroundMillis = ps.getForegroundTime(which) * 10;
+                    final long userMillis = ps.getUserTime(which);
+                    final long systemMillis = ps.getSystemTime(which);
+                    final long foregroundMillis = ps.getForegroundTime(which);
                     final int starts = ps.getStarts(which);
                     final int numCrashes = ps.getNumCrashes(which);
                     final int numAnrs = ps.getNumAnrs(which);
@@ -3135,6 +3151,35 @@
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
+        final long wifiIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
+        final long wifiRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
+        final long wifiTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
+        final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  WiFi Rx time:   "); formatTimeMs(sb, wifiRxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  WiFi Tx time:   "); formatTimeMs(sb, wifiTxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
         sb.setLength(0);
         sb.append(prefix);
                 sb.append("  Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
@@ -3162,9 +3207,41 @@
             sb.append(getPhoneDataConnectionCount(i, which));
             sb.append("x");
         }
+
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
+        final long bluetoothIdleTimeMs =
+                getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
+        final long bluetoothRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
+        final long bluetoothTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
+        final long bluetoothTotalTimeMs = bluetoothIdleTimeMs + bluetoothRxTimeMs +
+                bluetoothTxTimeMs;
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Bluetooth Rx time:   "); formatTimeMs(sb, bluetoothRxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Bluetooth Tx time:   "); formatTimeMs(sb, bluetoothTxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
         pw.println();
 
         if (which == STATS_SINCE_UNPLUGGED) {
@@ -3409,6 +3486,7 @@
             long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
             long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            int wifiScanCount = u.getWifiScanCount(which);
             long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileRxBytes > 0 || mobileTxBytes > 0
@@ -3444,7 +3522,7 @@
                         pw.print(" received, "); pw.print(wifiTxPackets); pw.println(" sent)");
             }
 
-            if (fullWifiLockOnTime != 0 || wifiScanTime != 0
+            if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
                     || uidWifiRunningTime != 0) {
                 sb.setLength(0);
                 sb.append(prefix); sb.append("    Wifi Running: ");
@@ -3458,7 +3536,9 @@
                 sb.append(prefix); sb.append("    Wifi Scan: ");
                         formatTimeMs(sb, wifiScanTime / 1000);
                         sb.append("("); sb.append(formatRatioLocked(wifiScanTime,
-                                whichBatteryRealtime)); sb.append(")");
+                                whichBatteryRealtime)); sb.append(") ");
+                                sb.append(wifiScanCount);
+                                sb.append("x");
                 pw.println(sb.toString());
             }
 
@@ -3717,9 +3797,9 @@
                         sb.append(prefix); sb.append("    Proc ");
                                 sb.append(ent.getKey()); sb.append(":\n");
                         sb.append(prefix); sb.append("      CPU: ");
-                                formatTime(sb, userTime); sb.append("usr + ");
-                                formatTime(sb, systemTime); sb.append("krn ; ");
-                                formatTime(sb, foregroundTime); sb.append("fg");
+                                formatTimeMs(sb, userTime); sb.append("usr + ");
+                                formatTimeMs(sb, systemTime); sb.append("krn ; ");
+                                formatTimeMs(sb, foregroundTime); sb.append("fg");
                         if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
                             sb.append("\n"); sb.append(prefix); sb.append("      ");
                             boolean hasOne = false;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index d03365b..512e212 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -63,7 +63,10 @@
      *
      * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
      * trace key file.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
 
     /**
@@ -760,7 +763,7 @@
     /**
      * Stop counting the number and aggregate size of memory allocations.
      *
-     * @see #startAllocCounting()
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
     @Deprecated
     public static void stopAllocCounting() {
@@ -770,7 +773,10 @@
     /**
      * Returns the global count of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalAllocCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
     }
@@ -778,7 +784,10 @@
     /**
      * Clears the global count of objects allocated.
      * @see #getGlobalAllocCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalAllocCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
     }
@@ -786,7 +795,10 @@
     /**
      * Returns the global size, in bytes, of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalAllocSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
     }
@@ -794,7 +806,10 @@
     /**
      * Clears the global size of objects allocated.
      * @see #getGlobalAllocSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalAllocSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
     }
@@ -802,7 +817,10 @@
     /**
      * Returns the global count of objects freed by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalFreedCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
     }
@@ -810,7 +828,10 @@
     /**
      * Clears the global count of objects freed.
      * @see #getGlobalFreedCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalFreedCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
     }
@@ -818,7 +839,10 @@
     /**
      * Returns the global size, in bytes, of objects freed by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalFreedSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
     }
@@ -826,7 +850,10 @@
     /**
      * Clears the global size of objects freed.
      * @see #getGlobalFreedSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalFreedSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
     }
@@ -834,7 +861,10 @@
     /**
      * Returns the number of non-concurrent GC invocations between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalGcInvocationCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
     }
@@ -842,7 +872,10 @@
     /**
      * Clears the count of non-concurrent GC invocations.
      * @see #getGlobalGcInvocationCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalGcInvocationCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
     }
@@ -851,7 +884,10 @@
      * Returns the number of classes successfully initialized (ie those that executed without
      * throwing an exception) between a {@link #startAllocCounting() start} and
      * {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalClassInitCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
     }
@@ -859,7 +895,10 @@
     /**
      * Clears the count of classes initialized.
      * @see #getGlobalClassInitCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalClassInitCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
     }
@@ -867,7 +906,10 @@
     /**
      * Returns the time spent successfully initializing classes between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalClassInitTime() {
         /* cumulative elapsed time for class initialization, in usec */
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
@@ -876,7 +918,10 @@
     /**
      * Clears the count of time spent initializing classes.
      * @see #getGlobalClassInitTime()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalClassInitTime() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
     }
@@ -948,7 +993,10 @@
     /**
      * Returns the thread-local count of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadAllocCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
     }
@@ -956,7 +1004,10 @@
     /**
      * Clears the thread-local count of objects allocated.
      * @see #getThreadAllocCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadAllocCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
     }
@@ -965,7 +1016,10 @@
      * Returns the thread-local size of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
      * @return The allocated size in bytes.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadAllocSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
     }
@@ -973,7 +1027,10 @@
     /**
      * Clears the thread-local count of objects allocated.
      * @see #getThreadAllocSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadAllocSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
     }
@@ -1013,7 +1070,10 @@
     /**
      * Returns the number of thread-local non-concurrent GC invocations between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadGcInvocationCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
     }
@@ -1021,7 +1081,10 @@
     /**
      * Clears the thread-local count of non-concurrent GC invocations.
      * @see #getThreadGcInvocationCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadGcInvocationCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
     }
@@ -1029,7 +1092,10 @@
     /**
      * Clears all the global and thread-local memory allocation counters.
      * @see #startAllocCounting()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetAllCounts() {
         VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
     }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 650f3b3..706e0d0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -391,6 +391,15 @@
     public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
 
     /**
+     * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction
+     * is always set for managed profiles.
+     * @hide
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_WALLPAPER = "no_wallpaper";
+
+    /**
      * Application restriction key that is used to indicate the pending arrival
      * of real restrictions for the app.
      *
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 1b226c1..3d57b4d 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -17,6 +17,7 @@
 package android.preference;
 
 
+import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.StringRes;
 import android.app.AlertDialog;
@@ -360,6 +361,7 @@
      * 
      * @param view The content View of the dialog, if it is custom.
      */
+    @CallSuper
     protected void onBindDialogView(View view) {
         View dialogMessageView = view.findViewById(com.android.internal.R.id.message);
         
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 78928b2..ccf2cfa 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.CallSuper;
 import com.android.internal.util.CharSequences;
 
 import android.annotation.DrawableRes;
@@ -508,6 +509,7 @@
      * @return The View that displays this Preference.
      * @see #onBindView(View)
      */
+    @CallSuper
     protected View onCreateView(ViewGroup parent) {
         final LayoutInflater layoutInflater =
             (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -537,6 +539,7 @@
      * @param view The View that shows this Preference.
      * @see #onCreateView(ViewGroup)
      */
+    @CallSuper
     protected void onBindView(View view) {
         final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title);
         if (titleView != null) {
@@ -1356,6 +1359,7 @@
      * should remove any references to this Preference that you know about. Make
      * sure to call through to the superclass implementation.
      */
+    @CallSuper
     protected void onPrepareForRemoval() {
         unregisterDependency();
     }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 2df9dbf..6517f35 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -328,6 +328,14 @@
         public static final String CACHED_PHOTO_ID = "photo_id";
 
         /**
+         * The cached photo URI of the picture associated with the phone number, if it exists.
+         * This value may not be current if the contact information associated with this number
+         * has changed.
+         * <P>Type: TEXT (URI)</P>
+         */
+        public static final String CACHED_PHOTO_URI = "photo_uri";
+
+        /**
          * The cached phone number, formatted with formatting rules based on the country the
          * user was in when the call was made or received.
          * This value is not guaranteed to be present, and may not be current if the contact
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 9cc12b5..91a19dc 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1010,7 +1010,8 @@
     /**
      * Types of data used to produce the display name for a contact. In the order
      * of increasing priority: {@link #EMAIL}, {@link #PHONE},
-     * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}.
+     * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_PHONETIC_NAME},
+     * {@link #STRUCTURED_NAME}.
      */
     public interface DisplayNameSources {
         public static final int UNDEFINED = 0;
@@ -1018,6 +1019,8 @@
         public static final int PHONE = 20;
         public static final int ORGANIZATION = 30;
         public static final int NICKNAME = 35;
+        /** Display name comes from a structured name that only has phonetic components. */
+        public static final int STRUCTURED_PHONETIC_NAME = 37;
         public static final int STRUCTURED_NAME = 40;
     }
 
@@ -4597,6 +4600,15 @@
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
 
         /**
+        * The content:// style URI for this table in managed profile, which requests a directory
+        * of data rows matching the selection criteria.
+        *
+        * @hide
+        */
+        static final Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
+                "data_enterprise");
+
+        /**
          * A boolean parameter for {@link Data#CONTENT_URI}.
          * This specifies whether or not the returned data items should be filtered to show
          * data items belonging to visible contacts only.
@@ -5748,6 +5760,20 @@
                     "phones");
 
             /**
+            * URI used for getting all contacts from primary and managed profile.
+            *
+            * It supports the same semantics as {@link #CONTENT_URI} and returns the same
+            * columns.  If the device has no corp profile that is linked to the current profile, it
+            * behaves in the exact same way as {@link #CONTENT_URI}.  If there is a corp profile
+            * linked to the current profile, it will merge corp profile and current profile's
+            * results and return
+            *
+            * @hide
+            */
+            public static final Uri ENTERPRISE_CONTENT_URI =
+                    Uri.withAppendedPath(Data.ENTERPRISE_CONTENT_URI, "phones");
+
+            /**
              * The content:// style URL for phone lookup using a filter. The filter returns
              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
              * to display names as well as phone numbers. The filter argument should be passed
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 1316471..6979bee 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -28,6 +28,7 @@
 import static android.provider.DocumentsContract.getTreeDocumentId;
 import static android.provider.DocumentsContract.isTreeUri;
 
+import android.annotation.CallSuper;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -541,6 +542,7 @@
      *
      * @see DocumentsContract#buildDocumentUriUsingTree(Uri, String)
      */
+    @CallSuper
     @Override
     public Uri canonicalize(Uri uri) {
         final Context context = getContext();
@@ -616,6 +618,7 @@
      * call the superclass. If the superclass returns {@code null}, the subclass
      * may implement custom behavior.
      */
+    @CallSuper
     @Override
     public Bundle call(String method, String arg, Bundle extras) {
         if (!method.startsWith("android:")) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c60a906..cc84932 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2254,54 +2254,66 @@
         /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_RING = "volume_ring";
 
         /**
          * System/notifications volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_SYSTEM = "volume_system";
 
         /**
          * Voice call volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_VOICE = "volume_voice";
 
         /**
          * Music/media/gaming volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_MUSIC = "volume_music";
 
         /**
          * Alarm volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_ALARM = "volume_alarm";
 
         /**
          * Notification volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_NOTIFICATION = "volume_notification";
 
         /**
          * Bluetooth Headset volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
 
         /**
          * Master volume (float in the range 0.0f to 1.0f).
+         *
          * @hide
          */
         public static final String VOLUME_MASTER = "volume_master";
 
-        private static final Validator VOLUME_MASTER_VALIDATOR =
-                new InclusiveFloatRangeValidator(0, 1);
-
         /**
          * Master volume mute (int 1 = mute, 0 = not muted).
          *
@@ -2358,6 +2370,8 @@
 
         /**
          * The mapping of stream type (integer) to its setting.
+         *
+         * @removed  Not used by anything since API 2.
          */
         public static final String[] VOLUME_SETTINGS = {
             VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC,
@@ -2368,6 +2382,8 @@
          * Appended to various volume related settings to record the previous
          * values before they the settings were affected by a silent/vibrate
          * ringer mode change.
+         *
+         * @removed  Not used by anything since API 2.
          */
         public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
 
@@ -2981,20 +2997,6 @@
             SCREEN_AUTO_BRIGHTNESS_ADJ,
             VIBRATE_INPUT_DEVICES,
             MODE_RINGER_STREAMS_AFFECTED,
-            VOLUME_VOICE,
-            VOLUME_SYSTEM,
-            VOLUME_RING,
-            VOLUME_MUSIC,
-            VOLUME_ALARM,
-            VOLUME_NOTIFICATION,
-            VOLUME_BLUETOOTH_SCO,
-            VOLUME_VOICE + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_SYSTEM + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_RING + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_MUSIC + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_ALARM + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_NOTIFICATION + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_BLUETOOTH_SCO + APPEND_FOR_LAST_AUDIBLE,
             TEXT_AUTO_REPLACE,
             TEXT_AUTO_CAPS,
             TEXT_AUTO_PUNCTUATE,
@@ -3167,7 +3169,6 @@
             VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
             VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
             VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
-            VALIDATORS.put(VOLUME_MASTER, VOLUME_MASTER_VALIDATOR);
             VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
             VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
             VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
diff --git a/media/java/android/media/midi/IMidiListener.aidl b/core/java/android/service/chooser/ChooserTarget.aidl
similarity index 66%
copy from media/java/android/media/midi/IMidiListener.aidl
copy to core/java/android/service/chooser/ChooserTarget.aidl
index a4129e9..ca91bc8 100644
--- a/media/java/android/media/midi/IMidiListener.aidl
+++ b/core/java/android/service/chooser/ChooserTarget.aidl
@@ -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,6 @@
  * limitations under the License.
  */
 
-package android.media.midi;
+package android.service.chooser;
 
-import android.media.midi.MidiDeviceInfo;
-
-/** @hide */
-oneway interface IMidiListener
-{
-    void onDeviceAdded(in MidiDeviceInfo device);
-    void onDeviceRemoved(in MidiDeviceInfo device);
-}
+parcelable ChooserTarget;
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
new file mode 100644
index 0000000..7fd1d10
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -0,0 +1,248 @@
+/*
+ * 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.service.chooser;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A ChooserTarget represents a deep-link into an application as returned by a
+ * {@link android.service.chooser.ChooserTargetService}.
+ */
+public final class ChooserTarget implements Parcelable {
+    private static final String TAG = "ChooserTarget";
+
+    /**
+     * The title of this target that will be shown to the user. The title may be truncated
+     * if it is too long to display in the space provided.
+     */
+    private CharSequence mTitle;
+
+    /**
+     * The icon that will be shown to the user to represent this target.
+     * The system may resize this icon as appropriate.
+     */
+    private Bitmap mIcon;
+
+    /**
+     * The IntentSender that will be used to deliver the intent to the target.
+     * It will be {@link android.content.Intent#fillIn(android.content.Intent, int)} filled in}
+     * by the real intent sent by the application.
+     */
+    private IntentSender mIntentSender;
+
+    /**
+     * The score given to this item. It can be normalized.
+     */
+    private float mScore;
+
+    /**
+     * Construct a deep link target for presentation by a chooser UI.
+     *
+     * <p>A target is composed of a title and an icon for presentation to the user.
+     * The UI presenting this target may truncate the title if it is too long to be presented
+     * in the available space, as well as crop, resize or overlay the supplied icon.</p>
+     *
+     * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
+     * to the other targets supplied by the same
+     * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
+     * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).</p>
+     *
+     * <p>Before being sent, the PendingIntent supplied will be
+     * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
+     * to the chooser. When constructing a PendingIntent for use in a ChooserTarget, make sure
+     * that you permit the relevant fields to be filled in using the appropriate flags such as
+     * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
+     * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
+     * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
+     * for {@link Intent#ACTION_SEND} intents.</p>
+     *
+     * <p>Take care not to place custom {@link android.os.Parcelable} types into
+     * the PendingIntent as extras, as the system will not be able to unparcel it to merge
+     * additional extras.</p>
+     *
+     * @param title title of this target that will be shown to a user
+     * @param icon icon to represent this target
+     * @param score ranking score for this target between 0.0f and 1.0f, inclusive
+     * @param pendingIntent PendingIntent to fill in and send if the user chooses this target
+     */
+    public ChooserTarget(CharSequence title, Bitmap icon, float score,
+            PendingIntent pendingIntent) {
+        this(title, icon, score, pendingIntent.getIntentSender());
+    }
+
+    /**
+     * Construct a deep link target for presentation by a chooser UI.
+     *
+     * <p>A target is composed of a title and an icon for presentation to the user.
+     * The UI presenting this target may truncate the title if it is too long to be presented
+     * in the available space, as well as crop, resize or overlay the supplied icon.</p>
+     *
+     * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
+     * to the other targets supplied by the same
+     * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
+     * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).</p>
+     *
+     * <p>Before being sent, the IntentSender supplied will be
+     * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
+     * to the chooser. When constructing an IntentSender for use in a ChooserTarget, make sure
+     * that you permit the relevant fields to be filled in using the appropriate flags such as
+     * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
+     * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
+     * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
+     * for {@link Intent#ACTION_SEND} intents.</p>
+     *
+     * <p>Take care not to place custom {@link android.os.Parcelable} types into
+     * the IntentSender as extras, as the system will not be able to unparcel it to merge
+     * additional extras.</p>
+     *
+     * @param title title of this target that will be shown to a user
+     * @param icon icon to represent this target
+     * @param score ranking score for this target between 0.0f and 1.0f, inclusive
+     * @param intentSender IntentSender to fill in and send if the user chooses this target
+     */
+    public ChooserTarget(CharSequence title, Bitmap icon, float score, IntentSender intentSender) {
+        mTitle = title;
+        mIcon = icon;
+        if (score > 1.f || score < 0.f) {
+            throw new IllegalArgumentException("Score " + score + " out of range; "
+                    + "must be between 0.0f and 1.0f");
+        }
+        mScore = score;
+        mIntentSender = intentSender;
+    }
+
+    ChooserTarget(Parcel in) {
+        mTitle = in.readCharSequence();
+        if (in.readInt() != 0) {
+            mIcon = Bitmap.CREATOR.createFromParcel(in);
+        } else {
+            mIcon = null;
+        }
+        mScore = in.readFloat();
+        mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
+    }
+
+    /**
+     * Returns the title of this target for display to a user. The UI displaying the title
+     * may truncate this title if it is too long to be displayed in full.
+     *
+     * @return the title of this target, intended to be shown to a user
+     */
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Returns the icon representing this target for display to a user. The UI displaying the icon
+     * may crop, resize or overlay this icon.
+     *
+     * @return the icon representing this target, intended to be shown to a user
+     */
+    public Bitmap getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Returns the ranking score supplied by the creator of this ChooserTarget.
+     * Values are between 0.0f and 1.0f. The UI displaying the target may
+     * take this score into account when sorting and merging targets from multiple sources.
+     *
+     * @return the ranking score for this target between 0.0f and 1.0f, inclusive
+     */
+    public float getScore() {
+        return mScore;
+    }
+
+    /**
+     * Returns the raw IntentSender supplied by the ChooserTarget's creator.
+     *
+     * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
+     *
+     * @return the IntentSender supplied by the ChooserTarget's creator
+     */
+    public IntentSender getIntentSender() {
+        return mIntentSender;
+    }
+
+    /**
+     * Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
+     *
+     * @param context the sending Context; generally the Activity presenting the chooser UI
+     * @param fillInIntent the Intent provided to the Chooser to be sent to a selected target
+     * @return true if sending the Intent was successful
+     */
+    public boolean sendIntent(Context context, Intent fillInIntent) {
+        if (fillInIntent != null) {
+            fillInIntent.migrateExtraStreamToClipData();
+            fillInIntent.prepareToLeaveProcess();
+        }
+        try {
+            mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
+            return true;
+        } catch (IntentSender.SendIntentException e) {
+            Log.e(TAG, "sendIntent " + this + " failed", e);
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ChooserTarget{" + mIntentSender.getCreatorPackage() + "'" + mTitle
+                + "', " + mScore + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeCharSequence(mTitle);
+        if (mIcon != null) {
+            dest.writeInt(1);
+            mIcon.writeToParcel(dest, 0);
+        } else {
+            dest.writeInt(0);
+        }
+        dest.writeFloat(mScore);
+        IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
+    }
+
+    public static final Creator<ChooserTarget> CREATOR
+            = new Creator<ChooserTarget>() {
+        @Override
+        public ChooserTarget createFromParcel(Parcel source) {
+            return new ChooserTarget(source);
+        }
+
+        @Override
+        public ChooserTarget[] newArray(int size) {
+            return new ChooserTarget[size];
+        }
+    };
+}
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
new file mode 100644
index 0000000..9188806
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -0,0 +1,130 @@
+/*
+ * 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.service.chooser;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * A service that receives calls from the system when the user is asked to choose
+ * a target for an intent explicitly by another app. The calling app must have invoked
+ * {@link android.content.Intent#ACTION_CHOOSER ACTION_CHOOSER} as handled by the system;
+ * applications do not have the ability to query a ChooserTargetService directly.
+ *
+ * <p>Which ChooserTargetServices are queried depends on a system-level policy decision
+ * made at the moment the chooser is invoked, including but not limited to user time
+ * spent with the app package or associated components in the foreground, recency of usage
+ * or frequency of usage. These will generally correlate with the order that app targets
+ * are shown in the list of intent handlers shown in the system chooser or resolver.</p>
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_CHOOSER_TARGET_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ *     &lt;service android:name=".ChooserTargetService"
+ *             android:label="&#64;string/service_name"
+ *             android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
+ *         &lt;intent-filter>
+ *             &lt;action android:name="android.service.chooser.ChooserTargetService" />
+ *         &lt;/intent-filter>
+ *     &lt;/service>
+ * </pre>
+ *
+ * <p>For the system to query your service, you must add a &lt;meta-data> element to the
+ * Activity in your manifest that can handle Intents that you would also like to provide
+ * optional deep links for. For example, a chat app might offer deep links to recent active
+ * conversations instead of invoking a generic picker after the app itself is chosen as a target.
+ * </p>
+ *
+ * <p>The meta-data element should have the name
+ * <code>android.service.chooser.chooser_target_service</code> and a value corresponding to
+ * the component name of your service. Example:</p>
+ * <pre>
+ *     &lt;activity android:name=".MyShareActivity"
+ *             android:label="&#64;string/share_activity_label">
+ *         &lt;intent-filter>
+ *             &lt;action android:name="android.intent.action.SEND" />
+ *         &lt;/intent-filter>
+ *         &lt;meta-data android:name="android.service.chooser.chooser_target_service"
+ *                 android:value=".ChooserTargetService" />
+ *     &lt;/activity>
+ * </pre>
+ */
+public abstract class ChooserTargetService extends Service {
+    // TAG = "ChooserTargetService[MySubclass]";
+    private final String TAG = ChooserTargetService.class.getSimpleName()
+            + '[' + getClass().getSimpleName() + ']';
+
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+
+    private IChooserTargetServiceWrapper mWrapper = null;
+
+    /**
+     * Called by the system to retrieve a set of deep-link {@link ChooserTarget targets} that
+     * can handle an intent.
+     *
+     * <p>The returned list should be sorted such that the most relevant targets appear first.
+     * Any PendingIntents used to construct the resulting ChooserTargets should always be prepared
+     * to have the relevant data fields filled in by the sender. See
+     * {@link ChooserTarget#ChooserTarget(CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent) ChooserTarget}.</p>
+     *
+     * <p><em>Important:</em> Calls to this method from other applications will occur on
+     * a binder thread, not on your app's main thread. Make sure that access to relevant data
+     * within your app is thread-safe.</p>
+     *
+     * @param targetActivityName the ComponentName of the matched activity that referred the system
+     *                           to this ChooserTargetService
+     * @param matchedFilter the specific IntentFilter on the component that was matched
+     * @return a list of deep-link targets to fulfill the intent match, sorted by relevance
+     */
+    public abstract List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName,
+            IntentFilter matchedFilter);
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            return null;
+        }
+
+        if (mWrapper == null) {
+            mWrapper = new IChooserTargetServiceWrapper();
+        }
+        return mWrapper;
+    }
+
+    private class IChooserTargetServiceWrapper extends IChooserTargetService.Stub {
+        @Override
+        public void getChooserTargets(ComponentName targetComponentName,
+                IntentFilter matchedFilter, IChooserTargetResult result) throws RemoteException {
+            List<ChooserTarget> targets = null;
+            try {
+                targets = onGetChooserTargets(targetComponentName, matchedFilter);
+            } finally {
+                result.sendResult(targets);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/midi/IMidiListener.aidl b/core/java/android/service/chooser/IChooserTargetResult.aidl
similarity index 67%
copy from media/java/android/media/midi/IMidiListener.aidl
copy to core/java/android/service/chooser/IChooserTargetResult.aidl
index a4129e9..dbd7cbd 100644
--- a/media/java/android/media/midi/IMidiListener.aidl
+++ b/core/java/android/service/chooser/IChooserTargetResult.aidl
@@ -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 android.media.midi;
+package android.service.chooser;
 
-import android.media.midi.MidiDeviceInfo;
+import android.service.chooser.ChooserTarget;
 
-/** @hide */
-oneway interface IMidiListener
+/**
+ * @hide
+ */
+interface IChooserTargetResult
 {
-    void onDeviceAdded(in MidiDeviceInfo device);
-    void onDeviceRemoved(in MidiDeviceInfo device);
+    void sendResult(in List<ChooserTarget> targets);
 }
diff --git a/core/java/android/service/chooser/IChooserTargetService.aidl b/core/java/android/service/chooser/IChooserTargetService.aidl
new file mode 100644
index 0000000..6cfa9a2
--- /dev/null
+++ b/core/java/android/service/chooser/IChooserTargetService.aidl
@@ -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 android.service.chooser;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.service.chooser.IChooserTargetResult;
+
+/**
+ * @hide
+ */
+oneway interface IChooserTargetService
+{
+    void getChooserTargets(in ComponentName targetComponentName,
+            in IntentFilter matchedFilter, IChooserTargetResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 77ef1da..1bdaef0 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -270,22 +270,30 @@
         // generate new layout for affected text
 
         StaticLayout reflowed;
+        StaticLayout.Builder b;
 
         synchronized (sLock) {
             reflowed = sStaticLayout;
+            b = sBuilder;
             sStaticLayout = null;
+            sBuilder = null;
         }
 
+        // TODO: make sure reflowed is properly initialized
         if (reflowed == null) {
             reflowed = new StaticLayout(null);
-        } else {
-            reflowed.prepare();
+            b = StaticLayout.Builder.obtain();
         }
 
-        reflowed.generate(text, where, where + after,
-                getPaint(), getWidth(), getTextDirectionHeuristic(), getSpacingMultiplier(),
-                getSpacingAdd(), false,
-                true, mEllipsizedWidth, mEllipsizeAt);
+        b.setText(text, where, where + after)
+                .setPaint(getPaint())
+                .setWidth(getWidth())
+                .setTextDir(getTextDirectionHeuristic())
+                .setSpacingMult(getSpacingMultiplier())
+                .setSpacingAdd(getSpacingAdd())
+                .setEllipsizedWidth(mEllipsizedWidth)
+                .setEllipsize(mEllipsizeAt);
+        reflowed.generate(b, false, true);
         int n = reflowed.getLineCount();
 
         // If the new layout has a blank line at the end, but it is not
@@ -359,9 +367,10 @@
 
         updateBlocks(startline, endline - 1, n);
 
+        b.finish();
         synchronized (sLock) {
             sStaticLayout = reflowed;
-            reflowed.finish();
+            sBuilder = b;
         }
     }
 
@@ -720,7 +729,8 @@
 
     private int mTopPadding, mBottomPadding;
 
-    private static StaticLayout sStaticLayout = new StaticLayout(null);
+    private static StaticLayout sStaticLayout = null;
+    private static StaticLayout.Builder sBuilder = null;
 
     private static final Object[] sLock = new Object[0];
 
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index e72e18f..832002c 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -66,21 +66,28 @@
     }
 
     static MeasuredText recycle(MeasuredText mt) {
-        mt.mText = null;
-        if (mt.mLen < 1000) {
-            synchronized(sLock) {
-                for (int i = 0; i < sCached.length; ++i) {
-                    if (sCached[i] == null) {
-                        sCached[i] = mt;
-                        mt.mText = null;
-                        break;
-                    }
+        mt.finish();
+        synchronized(sLock) {
+            for (int i = 0; i < sCached.length; ++i) {
+                if (sCached[i] == null) {
+                    sCached[i] = mt;
+                    mt.mText = null;
+                    break;
                 }
             }
         }
         return null;
     }
 
+    void finish() {
+        mText = null;
+        if (mLen > 1000) {
+            mWidths = null;
+            mChars = null;
+            mLevels = null;
+        }
+    }
+
     void setPos(int pos) {
         mPos = pos - mTextStart;
     }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ffb7d36..967e80c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -28,6 +28,7 @@
 import com.android.internal.util.GrowingArrayUtils;
 
 import java.util.Arrays;
+import java.util.Locale;
 
 /**
  * StaticLayout is a Layout for text that will not be edited after it
@@ -43,6 +44,179 @@
 
     static final String TAG = "StaticLayout";
 
+    /**
+     * Builder for static layouts. It would be better if this were a public
+     * API (as it would offer much greater flexibility for adding new options)
+     * but for the time being it's just internal.
+     *
+     * @hide
+     */
+    public final static class Builder {
+        private Builder() {
+            mNativePtr = nNewBuilder();
+        }
+
+        static Builder obtain() {
+            Builder b = null;
+            synchronized (sLock) {
+                for (int i = 0; i < sCached.length; i++) {
+                    if (sCached[i] != null) {
+                        b = sCached[i];
+                        sCached[i] = null;
+                        break;
+                    }
+                }
+            }
+            if (b == null) {
+                b = new Builder();
+            }
+
+            // set default initial values
+            b.mWidth = 0;
+            b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
+            b.mSpacingMult = 1.0f;
+            b.mSpacingAdd = 0.0f;
+            b.mIncludePad = true;
+            b.mEllipsizedWidth = 0;
+            b.mEllipsize = null;
+            b.mMaxLines = Integer.MAX_VALUE;
+
+            b.mMeasuredText = MeasuredText.obtain();
+            return b;
+        }
+
+        static void recycle(Builder b) {
+            b.mPaint = null;
+            b.mText = null;
+            MeasuredText.recycle(b.mMeasuredText);
+            synchronized (sLock) {
+                for (int i = 0; i < sCached.length; i++) {
+                    if (sCached[i] == null) {
+                        sCached[i] = b;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // release any expensive state
+        /* package */ void finish() {
+            nFinishBuilder(mNativePtr);
+            mMeasuredText.finish();
+        }
+
+        public Builder setText(CharSequence source) {
+            return setText(source, 0, source.length());
+        }
+
+        public Builder setText(CharSequence source, int start, int end) {
+            mText = source;
+            mStart = start;
+            mEnd = end;
+            return this;
+        }
+
+        public Builder setPaint(TextPaint paint) {
+            mPaint = paint;
+            return this;
+        }
+
+        public Builder setWidth(int width) {
+            mWidth = width;
+            if (mEllipsize == null) {
+                mEllipsizedWidth = width;
+            }
+            return this;
+        }
+
+        public Builder setTextDir(TextDirectionHeuristic textDir) {
+            mTextDir = textDir;
+            return this;
+        }
+
+        // TODO: combine the following, as they're almost always set together?
+        public Builder setSpacingMult(float spacingMult) {
+            mSpacingMult = spacingMult;
+            return this;
+        }
+
+        public Builder setSpacingAdd(float spacingAdd) {
+            mSpacingAdd = spacingAdd;
+            return this;
+        }
+
+        public Builder setIncludePad(boolean includePad) {
+            mIncludePad = includePad;
+            return this;
+        }
+
+        // TODO: combine the following?
+        public Builder setEllipsizedWidth(int ellipsizedWidth) {
+            mEllipsizedWidth = ellipsizedWidth;
+            return this;
+        }
+
+        public Builder setEllipsize(TextUtils.TruncateAt ellipsize) {
+            mEllipsize = ellipsize;
+            return this;
+        }
+
+        public Builder setMaxLines(int maxLines) {
+            mMaxLines = maxLines;
+            return this;
+        }
+
+        /* @hide */
+        public void setLocale(Locale locale) {
+            if (!locale.equals(mLocale)) {
+                nBuilderSetLocale(mNativePtr, locale.toLanguageTag());
+                mLocale = locale;
+            }
+        }
+
+        public StaticLayout build() {
+            // TODO: can optimize based on whether ellipsis is needed
+            StaticLayout result = new StaticLayout(mText);
+            result.initFromBuilder(this);
+            recycle(this);
+            return result;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                nFreeBuilder(mNativePtr);
+            } finally {
+                super.finalize();
+            }
+        }
+
+        /* package */ long mNativePtr;
+
+        CharSequence mText;
+        int mStart;
+        int mEnd;
+        TextPaint mPaint;
+        int mWidth;
+        TextDirectionHeuristic mTextDir;
+        float mSpacingMult;
+        float mSpacingAdd;
+        boolean mIncludePad;
+        int mEllipsizedWidth;
+        TextUtils.TruncateAt mEllipsize;
+        int mMaxLines;
+
+        Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
+
+        // This will go away and be subsumed by native builder code
+        MeasuredText mMeasuredText;
+
+        Locale mLocale;
+
+        private static final Object sLock = new Object();
+        private static final Builder[] sCached = new Builder[3];
+    }
+
     public StaticLayout(CharSequence source, TextPaint paint,
                         int width,
                         Alignment align, float spacingmult, float spacingadd,
@@ -110,6 +284,17 @@
                     : new Ellipsizer(source),
               paint, outerwidth, align, textDir, spacingmult, spacingadd);
 
+        Builder b = Builder.obtain();
+        b.setText(source, bufstart, bufend)
+            .setPaint(paint)
+            .setWidth(outerwidth)
+            .setTextDir(textDir)
+            .setSpacingMult(spacingmult)
+            .setSpacingAdd(spacingadd)
+            .setIncludePad(includepad)
+            .setEllipsizedWidth(ellipsizedWidth)
+            .setEllipsize(ellipsize)
+            .setMaxLines(maxLines);
         /*
          * This is annoying, but we can't refer to the layout until
          * superclass construction is finished, and the superclass
@@ -136,14 +321,9 @@
         mLines = new int[mLineDirections.length];
         mMaximumVisibleLineCount = maxLines;
 
-        mMeasured = MeasuredText.obtain();
+        initFromBuilder(b);
 
-        generate(source, bufstart, bufend, paint, outerwidth, textDir, spacingmult,
-                 spacingadd, includepad, includepad, ellipsizedWidth,
-                 ellipsize);
-
-        mMeasured = MeasuredText.recycle(mMeasured);
-        mFontMetricsInt = null;
+        Builder.recycle(b);
     }
 
     /* package */ StaticLayout(CharSequence text) {
@@ -152,33 +332,40 @@
         mColumns = COLUMNS_ELLIPSIZE;
         mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
         mLines = new int[mLineDirections.length];
-        // FIXME This is never recycled
-        mMeasured = MeasuredText.obtain();
     }
 
-    /* package */ void generate(CharSequence source, int bufStart, int bufEnd,
-                        TextPaint paint, int outerWidth,
-                        TextDirectionHeuristic textDir, float spacingmult,
-                        float spacingadd, boolean includepad,
-                        boolean trackpad, float ellipsizedWidth,
-                        TextUtils.TruncateAt ellipsize) {
-        LineBreaks lineBreaks = new LineBreaks();
+    private void initFromBuilder(Builder b) {
+        generate(b, b.mIncludePad, b.mIncludePad);
+    }
+
+    /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
+        CharSequence source = b.mText;
+        int bufStart = b.mStart;
+        int bufEnd = b.mEnd;
+        TextPaint paint = b.mPaint;
+        int outerWidth = b.mWidth;
+        TextDirectionHeuristic textDir = b.mTextDir;
+        float spacingmult = b.mSpacingMult;
+        float spacingadd = b.mSpacingAdd;
+        float ellipsizedWidth = b.mEllipsizedWidth;
+        TextUtils.TruncateAt ellipsize = b.mEllipsize;
+        LineBreaks lineBreaks = new LineBreaks();  // TODO: move to builder to avoid allocation costs
         // store span end locations
         int[] spanEndCache = new int[4];
         // store fontMetrics per span range
         // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
         int[] fmCache = new int[4 * 4];
-        final String localeLanguageTag = paint.getTextLocale().toLanguageTag();
+        b.setLocale(paint.getTextLocale());  // TODO: also respect LocaleSpan within the text
 
         mLineCount = 0;
 
         int v = 0;
         boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
 
-        Paint.FontMetricsInt fm = mFontMetricsInt;
+        Paint.FontMetricsInt fm = b.mFontMetricsInt;
         int[] chooseHtv = null;
 
-        MeasuredText measured = mMeasured;
+        MeasuredText measured = b.mMeasuredText;
 
         Spanned spanned = null;
         if (source instanceof Spanned)
@@ -306,7 +493,7 @@
                 }
             }
 
-            int breakCount = nComputeLineBreaks(localeLanguageTag, chs, widths, paraEnd - paraStart, firstWidth,
+            int breakCount = nComputeLineBreaks(b.mNativePtr, chs, widths, paraEnd - paraStart, firstWidth,
                     firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
                     lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
 
@@ -746,24 +933,21 @@
         return mEllipsizedWidth;
     }
 
-    void prepare() {
-        mMeasured = MeasuredText.obtain();
-    }
-    
-    void finish() {
-        mMeasured = MeasuredText.recycle(mMeasured);
-    }
-
     // populates LineBreaks and returns the number of breaks found
     //
     // the arrays inside the LineBreaks objects are passed in as well
     // to reduce the number of JNI calls in the common case where the
     // arrays do not have to be resized
-    private static native int nComputeLineBreaks(String locale, char[] text, float[] widths,
+    private static native int nComputeLineBreaks(long nativePtr, char[] text, float[] widths,
             int length, float firstWidth, int firstWidthLineCount, float restWidth,
             int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
             int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
 
+    private static native long nNewBuilder();
+    private static native void nFreeBuilder(long nativePtr);
+    private static native void nFinishBuilder(long nativePtr);
+    private static native void nBuilderSetLocale(long nativePtr, String locale);
+
     private int mLineCount;
     private int mTopPadding, mBottomPadding;
     private int mColumns;
@@ -793,12 +977,6 @@
 
     private static final double EXTRA_ROUNDING = 0.5;
 
-    /*
-     * This is reused across calls to generate()
-     */
-    private MeasuredText mMeasured;
-    private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
-
     // This is used to return three arrays from a single JNI call when
     // performing line breaking
     /*package*/ static class LineBreaks {
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index 0447117..4f8cff0 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.ColorInt;
 import android.graphics.Paint;
 
 /**
@@ -25,8 +26,10 @@
 public class TextPaint extends Paint {
 
     // Special value 0 means no background paint
+    @ColorInt
     public int bgColor;
     public int baselineShift;
+    @ColorInt
     public int linkColor;
     public int[] drawableState;
     public float density = 1.0f;
@@ -34,6 +37,7 @@
      * Special value 0 means no custom underline
      * @hide
      */
+    @ColorInt
     public int underlineColor = 0;
     /**
      * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java
index c9e09bd..f167aab 100644
--- a/core/java/android/text/style/ForegroundColorSpan.java
+++ b/core/java/android/text/style/ForegroundColorSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.ColorInt;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
@@ -26,7 +27,7 @@
 
     private final int mColor;
 
-    public ForegroundColorSpan(int color) {
+    public ForegroundColorSpan(@ColorInt int color) {
         mColor = color;
     }
 
@@ -46,6 +47,7 @@
         dest.writeInt(mColor);
     }
 
+    @ColorInt
     public int getForegroundColor() {
         return mColor;
     }
diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java
index 29dd273..17748ca 100644
--- a/core/java/android/text/style/QuoteSpan.java
+++ b/core/java/android/text/style/QuoteSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.ColorInt;
 import android.graphics.Paint;
 import android.graphics.Canvas;
 import android.os.Parcel;
@@ -34,7 +35,7 @@
         mColor = 0xff0000ff;
     }
     
-    public QuoteSpan(int color) {
+    public QuoteSpan(@ColorInt int color) {
         super();
         mColor = color;
     }
@@ -55,6 +56,7 @@
         dest.writeInt(mColor);
     }
 
+    @ColorInt
     public int getColor() {
         return mColor;
     }
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 68f725e..7da3941 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -475,6 +475,26 @@
     }
 
     /**
+     * Perform a {@link #remove(Object)} of all values in <var>array</var>
+     * @param array The array whose contents are to be removed.
+     */
+    public boolean removeAll(ArraySet<? extends E> array) {
+        // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first
+        //       pass, use the property that the sets are sorted by hash to make this linear passes
+        //       (except for hash collisions, which means worst case still n*m), then do one
+        //       collection pass into a new array. This avoids binary searches and excessive memcpy.
+        final int N = array.mSize;
+
+        // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all
+        //       the single results, compare size before and after.
+        final int originalSize = mSize;
+        for (int i = 0; i < N; i++) {
+            remove(array.valueAt(i));
+        }
+        return originalSize != mSize;
+    }
+
+    /**
      * Return the number of items in this array map.
      */
     @Override
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index f607207..84d9ce8 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -16,6 +16,7 @@
 
 package android.util;
 
+import java.io.PrintWriter;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Locale;
@@ -123,4 +124,83 @@
         }
     }
 
+    /** @hide */
+    public static void printSizeValue(PrintWriter pw, long number) {
+        float result = number;
+        String suffix = "";
+        if (result > 900) {
+            suffix = "KB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "MB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "GB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "TB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "PB";
+            result = result / 1024;
+        }
+        String value;
+        if (result < 1) {
+            value = String.format("%.2f", result);
+        } else if (result < 10) {
+            value = String.format("%.1f", result);
+        } else if (result < 100) {
+            value = String.format("%.0f", result);
+        } else {
+            value = String.format("%.0f", result);
+        }
+        pw.print(value);
+        pw.print(suffix);
+    }
+
+    /** @hide */
+    public static String sizeValueToString(long number, StringBuilder outBuilder) {
+        if (outBuilder == null) {
+            outBuilder = new StringBuilder(32);
+        }
+        float result = number;
+        String suffix = "";
+        if (result > 900) {
+            suffix = "KB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "MB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "GB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "TB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "PB";
+            result = result / 1024;
+        }
+        String value;
+        if (result < 1) {
+            value = String.format("%.2f", result);
+        } else if (result < 10) {
+            value = String.format("%.1f", result);
+        } else if (result < 100) {
+            value = String.format("%.0f", result);
+        } else {
+            value = String.format("%.0f", result);
+        }
+        outBuilder.append(value);
+        outBuilder.append(suffix);
+        return outBuilder.toString();
+    }
 }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/DisplayListCanvas.java
similarity index 84%
rename from core/java/android/view/GLES20Canvas.java
rename to core/java/android/view/DisplayListCanvas.java
index 0d36949..90e1f86 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.graphics.Bitmap;
 import android.graphics.CanvasProperty;
 import android.graphics.NinePatch;
@@ -24,19 +25,50 @@
 import android.graphics.Picture;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.util.Pools.SynchronizedPool;
 
 /**
- * An implementation of Canvas on top of OpenGL ES 2.0.
+ * An implementation of a GL canvas that records drawing operations.
+ * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
+ * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
+ * the DisplayList is still holding a native reference to the memory.
  */
-class GLES20Canvas extends HardwareCanvas {
+class DisplayListCanvas extends HardwareCanvas {
+    // The recording canvas pool should be large enough to handle a deeply nested
+    // view hierarchy because display lists are generated recursively.
+    private static final int POOL_LIMIT = 25;
+
+    private static final SynchronizedPool<DisplayListCanvas> sPool =
+            new SynchronizedPool<DisplayListCanvas>(POOL_LIMIT);
+
+    RenderNode mNode;
     private int mWidth;
     private int mHeight;
 
-    private float[] mPoint;
-    private float[] mLine;
 
-    private Rect mClipBounds;
-    private RectF mPathBounds;
+    static DisplayListCanvas obtain(@NonNull RenderNode node) {
+        if (node == null) throw new IllegalArgumentException("node cannot be null");
+        DisplayListCanvas canvas = sPool.acquire();
+        if (canvas == null) {
+            canvas = new DisplayListCanvas();
+        }
+        canvas.mNode = node;
+        return canvas;
+    }
+
+    void recycle() {
+        mNode = null;
+        sPool.release(this);
+    }
+
+    long finishRecording() {
+        return nFinishRecording(mNativeCanvasWrapper);
+    }
+
+    @Override
+    public boolean isRecordingFor(Object o) {
+        return o == mNode;
+    }
 
     ///////////////////////////////////////////////////////////////////////////
     // JNI
@@ -53,8 +85,8 @@
     // Constructors
     ///////////////////////////////////////////////////////////////////////////
 
-    // TODO: Merge with GLES20RecordingCanvas
-    protected GLES20Canvas() {
+
+    private DisplayListCanvas() {
         super(nCreateDisplayListRenderer());
     }
 
@@ -204,7 +236,7 @@
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
-        nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk,
+        nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
@@ -214,7 +246,7 @@
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
-        nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk,
+        nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
deleted file mode 100644
index 6c780c9..0000000
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.annotation.NonNull;
-import android.util.Pools.SynchronizedPool;
-
-/**
- * An implementation of a GL canvas that records drawing operations.
- * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
- * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
- * the DisplayList is still holding a native reference to the memory.
- */
-class GLES20RecordingCanvas extends GLES20Canvas {
-    // The recording canvas pool should be large enough to handle a deeply nested
-    // view hierarchy because display lists are generated recursively.
-    private static final int POOL_LIMIT = 25;
-
-    private static final SynchronizedPool<GLES20RecordingCanvas> sPool =
-            new SynchronizedPool<GLES20RecordingCanvas>(POOL_LIMIT);
-
-    RenderNode mNode;
-
-    private GLES20RecordingCanvas() {
-        super();
-    }
-
-    static GLES20RecordingCanvas obtain(@NonNull RenderNode node) {
-        if (node == null) throw new IllegalArgumentException("node cannot be null");
-        GLES20RecordingCanvas canvas = sPool.acquire();
-        if (canvas == null) {
-            canvas = new GLES20RecordingCanvas();
-        }
-        canvas.mNode = node;
-        return canvas;
-    }
-
-    void recycle() {
-        mNode = null;
-        sPool.release(this);
-    }
-
-    long finishRecording() {
-        return nFinishRecording(mNativeCanvasWrapper);
-    }
-
-    @Override
-    public boolean isRecordingFor(Object o) {
-        return o == mNode;
-    }
-}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index cdb350f..fc2b55b 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -119,6 +119,6 @@
             CanvasProperty<Paint> paint);
 
     public static void setProperty(String name, String value) {
-        GLES20Canvas.setProperty(name, value);
+        DisplayListCanvas.setProperty(name, value);
     }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 9921be2..afa7f51 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -205,7 +205,7 @@
      *         false otherwise
      */
     public static boolean isAvailable() {
-        return GLES20Canvas.isAvailable();
+        return DisplayListCanvas.isAvailable();
     }
 
     /**
@@ -423,7 +423,7 @@
      */
     static HardwareRenderer create(Context context, boolean translucent) {
         HardwareRenderer renderer = null;
-        if (GLES20Canvas.isAvailable()) {
+        if (DisplayListCanvas.isAvailable()) {
             renderer = new ThreadedRenderer(context, translucent);
         }
         return renderer;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 1014573..1a07aee 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -532,10 +532,10 @@
                 InflateException ex = new InflateException(e.getMessage());
                 ex.initCause(e);
                 throw ex;
-            } catch (IOException e) {
+            } catch (Exception e) {
                 InflateException ex = new InflateException(
                         parser.getPositionDescription()
-                        + ": " + e.getMessage());
+                                + ": " + e.getMessage());
                 ex.initCause(e);
                 throw ex;
             } finally {
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 09eb486..38867a8 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -225,7 +225,7 @@
      * @see #isValid()
      */
     public HardwareCanvas start(int width, int height) {
-        HardwareCanvas canvas = GLES20RecordingCanvas.obtain(this);
+        HardwareCanvas canvas = DisplayListCanvas.obtain(this);
         canvas.setViewport(width, height);
         // The dirty rect should always be null for a display list
         canvas.onPreDraw(null);
@@ -241,11 +241,11 @@
      * @see #isValid()
      */
     public void end(HardwareCanvas endCanvas) {
-        if (!(endCanvas instanceof GLES20RecordingCanvas)) {
+        if (!(endCanvas instanceof DisplayListCanvas)) {
             throw new IllegalArgumentException("Passed an invalid canvas to end!");
         }
 
-        GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas;
+        DisplayListCanvas canvas = (DisplayListCanvas) endCanvas;
         canvas.onPostDraw();
         long renderNodeData = canvas.finishRecording();
         nSetDisplayListData(mNativeRenderNode, renderNodeData);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 7b35a3b..379796d 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -283,10 +283,10 @@
     }
 
     public void setTarget(Canvas canvas) {
-        if (!(canvas instanceof GLES20RecordingCanvas)) {
+        if (!(canvas instanceof DisplayListCanvas)) {
             throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
         }
-        final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+        final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas;
         setTarget(recordingCanvas.mNode);
     }
 
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index df0838f..69b4c47 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -364,7 +364,7 @@
     @Override
     boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
         return nCopyLayerInto(mNativeProxy,
-                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+                layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
     }
 
     @Override
@@ -465,7 +465,7 @@
             for (int i = 0; i < count; i++) {
                 drawables.valueAt(i).addAtlasableBitmaps(tmpList);
                 for (int j = 0; j < tmpList.size(); j++) {
-                    preloadedPointers.add(tmpList.get(j).mNativeBitmap);
+                    preloadedPointers.add(tmpList.get(j).getSkBitmap());
                 }
                 tmpList.clear();
             }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f25b640..085a3f2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,11 +18,15 @@
 
 import android.animation.AnimatorInflater;
 import android.animation.StateListAnimator;
+import android.annotation.CallSuper;
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.FloatRange;
 import android.annotation.IdRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -5148,6 +5152,7 @@
      *        passed in as finer grained information about where the focus is coming
      *        from (in addition to direction).  Will be <code>null</code> otherwise.
      */
+    @CallSuper
     protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
             @Nullable Rect previouslyFocusedRect) {
         if (gainFocus) {
@@ -5370,6 +5375,7 @@
      * @see #sendAccessibilityEvent(int)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
+    @CallSuper
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
         if (mAccessibilityDelegate != null) {
             mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event);
@@ -5414,6 +5420,7 @@
      * @see #sendAccessibilityEvent(int)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
+    @CallSuper
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         if (mAccessibilityDelegate != null) {
             mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event);
@@ -5528,6 +5535,7 @@
      *
      * @param info The instance to initialize.
      */
+    @CallSuper
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         if (mAccessibilityDelegate != null) {
             mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info);
@@ -5849,7 +5857,7 @@
      *
      * @see AccessibilityDelegate
      */
-    public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+    public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
         mAccessibilityDelegate = delegate;
     }
 
@@ -6089,6 +6097,7 @@
      *
      * @hide pending API council approval
      */
+    @CallSuper
     protected void onFocusLost() {
         resetPressedState();
     }
@@ -10573,7 +10582,7 @@
      *
      * @attr ref android.R.styleable#View_alpha
      */
-    public void setAlpha(float alpha) {
+    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         ensureTransformationInfo();
         if (mTransformationInfo.mAlpha != alpha) {
             mTransformationInfo.mAlpha = alpha;
@@ -13080,6 +13089,7 @@
      *
      * @see #onDetachedFromWindow()
      */
+    @CallSuper
     protected void onAttachedToWindow() {
         if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
             mParent.requestTransparentRegion(this);
@@ -13412,6 +13422,7 @@
      *
      * @see #onAttachedToWindow()
      */
+    @CallSuper
     protected void onDetachedFromWindow() {
     }
 
@@ -13425,6 +13436,7 @@
      *
      * @hide
      */
+    @CallSuper
     protected void onDetachedFromWindowInternal() {
         mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
         mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
@@ -13731,6 +13743,7 @@
      * @see #dispatchSaveInstanceState(android.util.SparseArray)
      * @see #setSaveEnabled(boolean)
      */
+    @CallSuper
     protected Parcelable onSaveInstanceState() {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         return BaseSavedState.EMPTY_STATE;
@@ -13789,6 +13802,7 @@
      * @see #restoreHierarchyState(android.util.SparseArray)
      * @see #dispatchRestoreInstanceState(android.util.SparseArray)
      */
+    @CallSuper
     protected void onRestoreInstanceState(Parcelable state) {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         if (state != BaseSavedState.EMPTY_STATE && state != null) {
@@ -14039,6 +14053,7 @@
      *
      * @hide
      */
+    @CallSuper
     protected void destroyHardwareResources() {
         // Although the Layer will be destroyed by RenderNode, we want to release
         // the staging display list, which is also a signal to RenderNode that it's
@@ -14311,7 +14326,7 @@
      * @see #buildDrawingCache()
      * @see #getDrawingCache()
      */
-    public void setDrawingCacheBackgroundColor(int color) {
+    public void setDrawingCacheBackgroundColor(@ColorInt int color) {
         if (color != mDrawingCacheBackgroundColor) {
             mDrawingCacheBackgroundColor = color;
             mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
@@ -14323,6 +14338,7 @@
      *
      * @return The background color to used for the drawing cache's bitmap
      */
+    @ColorInt
     public int getDrawingCacheBackgroundColor() {
         return mDrawingCacheBackgroundColor;
     }
@@ -15227,6 +15243,7 @@
      *
      * @param canvas The Canvas to which the View is rendered.
      */
+    @CallSuper
     public void draw(Canvas canvas) {
         final int privateFlags = mPrivateFlags;
         final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
@@ -15536,6 +15553,7 @@
      * @return The known solid color background for this view, or 0 if the color may vary
      */
     @ViewDebug.ExportedProperty(category = "drawing")
+    @ColorInt
     public int getSolidColor() {
         return 0;
     }
@@ -15828,6 +15846,7 @@
      * <p>Even if the subclass overrides onFinishInflate, they should always be
      * sure to call the super method, so that we get called.
      */
+    @CallSuper
     protected void onFinishInflate() {
     }
 
@@ -15993,6 +16012,7 @@
      * @see #unscheduleDrawable(android.graphics.drawable.Drawable)
      * @see #drawableStateChanged()
      */
+    @CallSuper
     protected boolean verifyDrawable(Drawable who) {
         return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who);
     }
@@ -16008,6 +16028,7 @@
      *
      * @see Drawable#setState(int[])
      */
+    @CallSuper
     protected void drawableStateChanged() {
         final int[] state = getDrawableState();
 
@@ -16040,6 +16061,7 @@
      * @param x hotspot x coordinate
      * @param y hotspot y coordinate
      */
+    @CallSuper
     public void drawableHotspotChanged(float x, float y) {
         if (mBackground != null) {
             mBackground.setHotspot(x, y);
@@ -16222,7 +16244,7 @@
      * @param color the color of the background
      */
     @RemotableViewMethod
-    public void setBackgroundColor(int color) {
+    public void setBackgroundColor(@ColorInt int color) {
         if (mBackground instanceof ColorDrawable) {
             ((ColorDrawable) mBackground.mutate()).setColor(color);
             computeOpaqueFlags();
@@ -16238,6 +16260,7 @@
      *
      * @return The color of the ColorDrawable background, if set, otherwise 0.
      */
+    @ColorInt
     public int getBackgroundColor() {
         if (mBackground instanceof ColorDrawable) {
             return ((ColorDrawable) mBackground).getColor();
@@ -17011,7 +17034,7 @@
      *
      * @param location an array of two integers in which to hold the coordinates
      */
-    public void getLocationOnScreen(int[] location) {
+    public void getLocationOnScreen(@Size(2) int[] location) {
         getLocationInWindow(location);
 
         final AttachInfo info = mAttachInfo;
@@ -17028,7 +17051,7 @@
      *
      * @param location an array of two integers in which to hold the coordinates
      */
-    public void getLocationInWindow(int[] location) {
+    public void getLocationInWindow(@Size(2) int[] location) {
         if (location == null || location.length < 2) {
             throw new IllegalArgumentException("location must be an array of two integers");
         }
@@ -17512,6 +17535,7 @@
      * <p>Subclasses which override this method should call the superclass method to
      * handle possible request-during-layout errors correctly.</p>
      */
+    @CallSuper
     public void requestLayout() {
         if (mMeasureCache != null) mMeasureCache.clear();
 
@@ -17967,6 +17991,7 @@
      * @see #setAnimation(android.view.animation.Animation)
      * @see #getAnimation()
      */
+    @CallSuper
     protected void onAnimationStart() {
         mPrivateFlags |= PFLAG_ANIMATION_STARTED;
     }
@@ -17979,6 +18004,7 @@
      * @see #setAnimation(android.view.animation.Animation)
      * @see #getAnimation()
      */
+    @CallSuper
     protected void onAnimationEnd() {
         mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
     }
@@ -18871,7 +18897,7 @@
      * @see #dispatchNestedPreScroll(int, int, int[], int[])
      */
     public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
-            int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
+            int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) {
         if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
             if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
                 int startX = 0;
@@ -18919,7 +18945,8 @@
      * @return true if the parent consumed some or all of the scroll delta
      * @see #dispatchNestedScroll(int, int, int, int, int[])
      */
-    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+    public boolean dispatchNestedPreScroll(int dx, int dy,
+            @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) {
         if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
             if (dx != 0 || dy != 0) {
                 int startX = 0;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e332135..744f665 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
@@ -1069,7 +1070,7 @@
     public abstract void setTitle(CharSequence title);
 
     @Deprecated
-    public abstract void setTitleColor(int textColor);
+    public abstract void setTitleColor(@ColorInt int textColor);
 
     public abstract void openPanel(int featureId, KeyEvent event);
 
@@ -1835,6 +1836,7 @@
     /**
      * @return the color of the status bar.
      */
+    @ColorInt
     public abstract int getStatusBarColor();
 
     /**
@@ -1852,11 +1854,12 @@
      * The transitionName for the view background will be "android:status:background".
      * </p>
      */
-    public abstract void setStatusBarColor(int color);
+    public abstract void setStatusBarColor(@ColorInt int color);
 
     /**
      * @return the color of the navigation bar.
      */
+    @ColorInt
     public abstract int getNavigationBarColor();
 
     /**
@@ -1874,7 +1877,7 @@
      * The transitionName for the view background will be "android:navigation:background".
      * </p>
      */
-    public abstract void setNavigationBarColor(int color);
+    public abstract void setNavigationBarColor(@ColorInt int color);
 
 
 }
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 85d77cb..a5524d8 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -16,6 +16,7 @@
 
 package android.view.animation;
 
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.RectF;
@@ -622,7 +623,7 @@
      * @param bg The background color.  If 0, no background.  Currently must
      * be black, with any desired alpha level.
      */
-    public void setBackgroundColor(int bg) {
+    public void setBackgroundColor(@ColorInt int bg) {
         mBackgroundColor = bg;
     }
 
@@ -753,6 +754,7 @@
     /**
      * Returns the background color behind the animation.
      */
+    @ColorInt
     public int getBackgroundColor() {
         return mBackgroundColor;
     }
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index 30c12ed..8eb5b5c 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -16,6 +16,7 @@
 
 package android.view.animation;
 
+import android.annotation.FloatRange;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 
@@ -163,7 +164,7 @@
      * Sets the degree of transparency
      * @param alpha 1.0 means fully opaqe and 0.0 means fully transparent
      */
-    public void setAlpha(float alpha) {
+    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         mAlpha = alpha;
     }
 
diff --git a/core/java/android/webkit/WebResourceError.java b/core/java/android/webkit/WebResourceError.java
new file mode 100644
index 0000000..080d174
--- /dev/null
+++ b/core/java/android/webkit/WebResourceError.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 android.webkit;
+
+/**
+ * Encapsulates information about errors occured during loading of web resources. See
+ * {@link WebViewClient#onReceivedError(WebView, WebResourceRequest, WebResourceError) WebViewClient.onReceivedError(WebView, WebResourceRequest, WebResourceError)}
+ */
+public abstract class WebResourceError {
+    /**
+     * Gets the error code of the error. The code corresponds to one
+     * of the ERROR_* constants in {@link WebViewClient}.
+     *
+     * @return The error code of the error
+     */
+    public abstract int getErrorCode();
+
+    /**
+     * Gets the string describing the error. Descriptions are localized,
+     * and thus can be used for communicating the problem to the user.
+     *
+     * @return The description of the error
+     */
+    public abstract String getDescription();
+}
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index f487a4e..a42aaa7 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -25,7 +25,7 @@
  * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
  * response when the WebView requests a particular resource.
  */
-public class WebResourceResponse {
+public class WebResourceResponse extends WebResourceResponseBase {
     private String mMimeType;
     private String mEncoding;
     private int mStatusCode;
@@ -75,38 +75,36 @@
     }
 
     /**
-     * Sets the resource response's MIME type, for example text/html.
+     * Sets the resource response's MIME type, for example &quot;text/html&quot;.
      *
-     * @param mimeType the resource response's MIME type
+     * @param mimeType The resource response's MIME type
      */
     public void setMimeType(String mimeType) {
         mMimeType = mimeType;
     }
 
     /**
-     * Gets the resource response's MIME type.
-     *
-     * @return the resource response's MIME type
+     * {@inheritDoc}
      */
+    @Override
     public String getMimeType() {
         return mMimeType;
     }
 
     /**
-     * Sets the resource response's encoding, for example UTF-8. This is used
+     * Sets the resource response's encoding, for example &quot;UTF-8&quot;. This is used
      * to decode the data from the input stream.
      *
-     * @param encoding the resource response's encoding
+     * @param encoding The resource response's encoding
      */
     public void setEncoding(String encoding) {
         mEncoding = encoding;
     }
 
     /**
-     * Gets the resource response's encoding.
-     *
-     * @return the resource response's encoding
+     * {@inheritDoc}
      */
+    @Override
     public String getEncoding() {
         return mEncoding;
     }
@@ -142,19 +140,17 @@
     }
 
     /**
-     * Gets the resource response's status code.
-     *
-     * @return the resource response's status code.
+     * {@inheritDoc}
      */
+    @Override
     public int getStatusCode() {
         return mStatusCode;
     }
 
     /**
-     * Gets the description of the resource response's status code.
-     *
-     * @return the description of the resource response's status code.
+     * {@inheritDoc}
      */
+    @Override
     public String getReasonPhrase() {
         return mReasonPhrase;
     }
@@ -162,17 +158,16 @@
     /**
      * Sets the headers for the resource response.
      *
-     * @param headers mapping of header name -> header value.
+     * @param headers Mapping of header name -> header value.
      */
     public void setResponseHeaders(Map<String, String> headers) {
         mResponseHeaders = headers;
     }
 
     /**
-     * Gets the headers for the resource response.
-     *
-     * @return the headers for the resource response.
+     * {@inheritDoc}
      */
+    @Override
     public Map<String, String> getResponseHeaders() {
         return mResponseHeaders;
     }
@@ -190,15 +185,13 @@
             throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " +
                 "not be passed to a WebResourceResponse");
         }
-
         mInputStream = data;
     }
 
     /**
-     * Gets the input stream that provides the resource response's data.
-     *
-     * @return the input stream that provides the resource response's data
+     * {@inheritDoc}
      */
+    @Override
     public InputStream getData() {
         return mInputStream;
     }
diff --git a/core/java/android/webkit/WebResourceResponseBase.java b/core/java/android/webkit/WebResourceResponseBase.java
new file mode 100644
index 0000000..cffde82
--- /dev/null
+++ b/core/java/android/webkit/WebResourceResponseBase.java
@@ -0,0 +1,68 @@
+/*
+ * 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.webkit;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Encapsulates a resource response received from the server.
+ * This is an abstract class used by WebView callbacks.
+ */
+public abstract class WebResourceResponseBase {
+    /**
+     * Gets the resource response's MIME type.
+     *
+     * @return The resource response's MIME type
+     */
+    public abstract String getMimeType();
+
+    /**
+     * Gets the resource response's encoding.
+     *
+     * @return The resource response's encoding
+     */
+    public abstract String getEncoding();
+
+    /**
+     * Gets the resource response's status code.
+     *
+     * @return The resource response's status code.
+     */
+    public abstract int getStatusCode();
+
+    /**
+     * Gets the description of the resource response's status code.
+     *
+     * @return The description of the resource response's status code.
+     */
+    public abstract String getReasonPhrase();
+
+    /**
+     * Gets the headers for the resource response.
+     *
+     * @return The headers for the resource response.
+     */
+    public abstract Map<String, String> getResponseHeaders();
+
+    /**
+     * Gets the input stream that provides the resource response's data.
+     *
+     * @return The input stream that provides the resource response's data
+     */
+    public abstract InputStream getData();
+}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 1d2c311..3df1293 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1285,7 +1285,7 @@
      * strongly discouraged.
      *
      * @param mode The mixed content mode to use. One of {@link #MIXED_CONTENT_NEVER_ALLOW},
-     *     {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+     *     {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
      */
     public abstract void setMixedContentMode(int mode);
 
@@ -1293,7 +1293,7 @@
      * Gets the current behavior of the WebView with regard to loading insecure content from a
      * secure origin.
      * @return The current setting, one of {@link #MIXED_CONTENT_NEVER_ALLOW},
-     *     {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+     *     {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
      */
     public abstract int getMixedContentMode();
 
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 01f9b37..34b8cf6 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -174,6 +174,8 @@
     public static final int ERROR_FILE_NOT_FOUND = -14;
     /** Too many requests during this load */
     public static final int ERROR_TOO_MANY_REQUESTS = -15;
+    /** Request blocked by the browser */
+    public static final int ERROR_BLOCKED = -16;
 
     /**
      * Report an error to the host application. These errors are unrecoverable
@@ -183,12 +185,45 @@
      * @param errorCode The error code corresponding to an ERROR_* value.
      * @param description A String describing the error.
      * @param failingUrl The url that failed to load.
+     * @deprecated Use {@link #onReceivedError(WebView, WebResourceRequest, WebResourceError)
+     *             onReceivedError(WebView, WebResourceRequest, WebResourceError)} instead.
      */
+    @Deprecated
     public void onReceivedError(WebView view, int errorCode,
             String description, String failingUrl) {
     }
 
     /**
+     * Report web resource loading error to the host application. These errors usually indicate
+     * inability to connect to the server. Note that unlike the deprecated version of the callback,
+     * the new version will be called for any resource (iframe, image, etc), not just for the main
+     * page. Thus, it is recommended to perform minimum required work in this callback.
+     * @param view The WebView that is initiating the callback.
+     * @param request The originating request.
+     * @param error Information about the error occured.
+     */
+    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+        if (request.isForMainFrame()) {
+            onReceivedError(view,
+                    error.getErrorCode(), error.getDescription(), request.getUrl().toString());
+        }
+    }
+
+    /**
+     * Notify the host application that an HTTP error has been received from the server while
+     * loading a resource.  HTTP errors have status codes &gt;= 400.  This callback will be called
+     * for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to
+     * perform minimum required work in this callback. Note that the content of the server
+     * response may not be provided within the <b>errorResponse</b> parameter.
+     * @param view The WebView that is initiating the callback.
+     * @param request The originating request.
+     * @param errorResponse Information about the error occured.
+     */
+    public void onReceivedHttpError(
+            WebView view, WebResourceRequest request, WebResourceResponseBase errorResponse) {
+    }
+
+    /**
      * As the host application if the browser should resend data as the
      * requested page was a result of a POST. The default is to not resend the
      * data.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a6e2952..168066a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.content.Context;
 import android.content.Intent;
@@ -5982,7 +5983,7 @@
      *
      * @param color The background color
      */
-    public void setCacheColorHint(int color) {
+    public void setCacheColorHint(@ColorInt int color) {
         if (color != mCacheColorHint) {
             mCacheColorHint = color;
             int count = getChildCount();
@@ -6000,6 +6001,7 @@
      * @return The cache color hint
      */
     @ViewDebug.ExportedProperty(category = "drawing")
+    @ColorInt
     public int getCacheColorHint() {
         return mCacheColorHint;
     }
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 9b977fa..72cb0b5 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.database.DataSetObserver;
 import android.os.Parcelable;
@@ -276,7 +277,7 @@
      *
      * @param listener The callback that will be invoked.
      */
-    public void setOnItemClickListener(OnItemClickListener listener) {
+    public void setOnItemClickListener(@Nullable OnItemClickListener listener) {
         mOnItemClickListener = listener;
     }
 
@@ -284,6 +285,7 @@
      * @return The callback to be invoked with an item in this AdapterView has
      *         been clicked, or null id no callback has been set.
      */
+    @Nullable
     public final OnItemClickListener getOnItemClickListener() {
         return mOnItemClickListener;
     }
@@ -394,10 +396,11 @@
      *
      * @param listener The callback that will run
      */
-    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+    public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) {
         mOnItemSelectedListener = listener;
     }
 
+    @Nullable
     public final OnItemSelectedListener getOnItemSelectedListener() {
         return mOnItemSelectedListener;
     }
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index fd1c4b8..5bc16cb 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.Widget;
 import android.content.Context;
@@ -140,7 +141,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
      */
-    public void setSelectedWeekBackgroundColor(int color) {
+    public void setSelectedWeekBackgroundColor(@ColorInt int color) {
         mDelegate.setSelectedWeekBackgroundColor(color);
     }
 
@@ -151,6 +152,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
      */
+    @ColorInt
     public int getSelectedWeekBackgroundColor() {
         return mDelegate.getSelectedWeekBackgroundColor();
     }
@@ -162,7 +164,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
      */
-    public void setFocusedMonthDateColor(int color) {
+    public void setFocusedMonthDateColor(@ColorInt int color) {
         mDelegate.setFocusedMonthDateColor(color);
     }
 
@@ -173,6 +175,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
      */
+    @ColorInt
     public int getFocusedMonthDateColor() {
         return mDelegate.getFocusedMonthDateColor();
     }
@@ -184,7 +187,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
      */
-    public void setUnfocusedMonthDateColor(int color) {
+    public void setUnfocusedMonthDateColor(@ColorInt int color) {
         mDelegate.setUnfocusedMonthDateColor(color);
     }
 
@@ -195,6 +198,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
      */
+    @ColorInt
     public int getUnfocusedMonthDateColor() {
         return mDelegate.getUnfocusedMonthDateColor();
     }
@@ -206,7 +210,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekNumberColor
      */
-    public void setWeekNumberColor(int color) {
+    public void setWeekNumberColor(@ColorInt int color) {
         mDelegate.setWeekNumberColor(color);
     }
 
@@ -217,6 +221,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekNumberColor
      */
+    @ColorInt
     public int getWeekNumberColor() {
         return mDelegate.getWeekNumberColor();
     }
@@ -228,7 +233,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
      */
-    public void setWeekSeparatorLineColor(int color) {
+    public void setWeekSeparatorLineColor(@ColorInt int color) {
         mDelegate.setWeekSeparatorLineColor(color);
     }
 
@@ -239,6 +244,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
      */
+    @ColorInt
     public int getWeekSeparatorLineColor() {
         return mDelegate.getWeekSeparatorLineColor();
     }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 391347e..9019f31 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.content.res.TypedArray;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
@@ -292,7 +293,7 @@
      *
      * @param color Color in argb
      */
-    public void setColor(int color) {
+    public void setColor(@ColorInt int color) {
         mPaint.setColor(color);
     }
 
@@ -300,6 +301,7 @@
      * Return the color of this edge effect in argb.
      * @return The color of this edge effect in argb
      */
+    @ColorInt
     public int getColor() {
         return mPaint.getColor();
     }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f8e207f..cc44577 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -128,7 +128,7 @@
     // Each Editor manages its own undo stack.
     private final UndoManager mUndoManager = new UndoManager();
     private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
-    final InputFilter mUndoInputFilter = new UndoInputFilter(this);
+    final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this);
     boolean mAllowUndo = true;
 
     // Cursor Controllers.
@@ -217,6 +217,12 @@
     WordIterator mWordIterator;
     SpellChecker mSpellChecker;
 
+    // This word iterator is set with text and used to determine word boundaries
+    // when a user is selecting text.
+    private WordIterator mWordIteratorWithText;
+    // Indicate that the text in the word iterator needs to be updated.
+    private boolean mUpdateWordIteratorText;
+
     private Rect mTempRect;
 
     private TextView mTextView;
@@ -240,6 +246,15 @@
         mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
     }
 
+    /**
+     * Forgets all undo and redo operations for this Editor.
+     */
+    void forgetUndoRedo() {
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.forgetUndos(owners, -1 /* all */);
+        mUndoManager.forgetRedos(owners, -1 /* all */);
+    }
+
     boolean canUndo() {
         UndoOwner[] owners = { mUndoOwner };
         return mAllowUndo && mUndoManager.countUndos(owners) > 0;
@@ -689,9 +704,52 @@
         return mTextView.getTransformationMethod() instanceof PasswordTransformationMethod;
     }
 
+    private int getWordStart(int offset) {
+        // FIXME - For this and similar methods we're not doing anything to check if there's
+        // a LocaleSpan in the text, this may be something we should try handling or checking for.
+        int retOffset = getWordIteratorWithText().getBeginning(offset);
+        if (retOffset == BreakIterator.DONE) retOffset = offset;
+        return retOffset;
+    }
+
+    private int getWordEnd(int offset, boolean includePunctuation) {
+        int retOffset = getWordIteratorWithText().getEnd(offset);
+        if (retOffset == BreakIterator.DONE) {
+            retOffset = offset;
+        } else if (includePunctuation) {
+            retOffset = handlePunctuation(retOffset);
+        }
+        return retOffset;
+    }
+
+    private boolean isEndBoundary(int offset) {
+        int thisEnd = getWordEnd(offset, false);
+        return offset == thisEnd;
+    }
+
+    private boolean isStartBoundary(int offset) {
+        int thisStart = getWordStart(offset);
+        return thisStart == offset;
+    }
+
+    private int handlePunctuation(int offset) {
+        // FIXME - Check with UX how repeated ending punctuation should be handled.
+        // FIXME - Check with UX if / how we would handle non sentence ending characters.
+        // FIXME - Consider punctuation in different languages.
+        CharSequence text = mTextView.getText();
+        if (offset < text.length()) {
+            int c = Character.codePointAt(text, offset);
+            if (c == 0x002e /* period */|| c == 0x003f /* question mark */
+                    || c == 0x0021 /* exclamation mark */) {
+                offset = Character.offsetByCodePoints(text, offset, 1);
+            }
+        }
+        return offset;
+    }
+
     /**
-     * Adjusts selection to the word under last touch offset.
-     * Return true if the operation was successfully performed.
+     * Adjusts selection to the word under last touch offset. Return true if the operation was
+     * successfully performed.
      */
     private boolean selectCurrentWord() {
         if (!canSelectText()) {
@@ -738,6 +796,8 @@
             selectionStart = ((Spanned) mTextView.getText()).getSpanStart(urlSpan);
             selectionEnd = ((Spanned) mTextView.getText()).getSpanEnd(urlSpan);
         } else {
+            // FIXME - We should check if there's a LocaleSpan in the text, this may be
+            // something we should try handling or checking for.
             final WordIterator wordIterator = getWordIterator();
             wordIterator.setCharSequence(mTextView.getText(), minOffset, maxOffset);
 
@@ -760,6 +820,7 @@
     void onLocaleChanged() {
         // Will be re-created on demand in getWordIterator with the proper new locale
         mWordIterator = null;
+        mWordIteratorWithText = null;
     }
 
     /**
@@ -772,6 +833,23 @@
         return mWordIterator;
     }
 
+    private WordIterator getWordIteratorWithText() {
+        if (mWordIteratorWithText == null) {
+            mWordIteratorWithText = new WordIterator(mTextView.getTextServicesLocale());
+            mUpdateWordIteratorText = true;
+        }
+        if (mUpdateWordIteratorText) {
+            // FIXME - Shouldn't copy all of the text as only the area of the text relevant
+            // to the user's selection is needed. A possible solution would be to
+            // copy some number N of characters near the selection and then when the
+            // user approaches N then we'd do another copy of the next N characters.
+            CharSequence text = mTextView.getText();
+            mWordIteratorWithText.setCharSequence(text, 0, text.length());
+            mUpdateWordIteratorText = false;
+        }
+        return mWordIteratorWithText;
+    }
+
     private long getCharRange(int offset) {
         final int textLength = mTextView.getText().length();
         if (offset + 1 < textLength) {
@@ -920,9 +998,8 @@
                 mTextView.startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
                 stopSelectionActionMode();
             } else {
-                getSelectionController().hide();
-                selectCurrentWord();
-                getSelectionController().show();
+                stopSelectionActionMode();
+                startSelectionActionMode();
             }
             handled = true;
         }
@@ -1058,6 +1135,9 @@
     void sendOnTextChanged(int start, int after) {
         updateSpellCheckSpans(start, start + after, false);
 
+        // Flip flag to indicate the word iterator needs to have the text reset.
+        mUpdateWordIteratorText = true;
+
         // Hide the controllers as soon as text is modified (typing, procedural...)
         // We do not hide the span controllers, since they can be added when a new text is
         // inserted into the text view (voice IME).
@@ -1143,6 +1223,7 @@
                     ims.mChangedEnd = EXTRACT_UNKNOWN;
                     ims.mContentChanged = false;
                 }
+                mUndoInputFilter.beginBatchEdit();
                 mTextView.onBeginBatchEdit();
             }
         }
@@ -1169,6 +1250,7 @@
 
     void finishBatchEdit(final InputMethodState ims) {
         mTextView.onEndBatchEdit();
+        mUndoInputFilter.endBatchEdit();
 
         if (ims.mContentChanged || ims.mSelectionModeChanged) {
             mTextView.updateAfterEdit();
@@ -1613,6 +1695,9 @@
             }
         }
 
+        if (selectionStarted) {
+            getSelectionController().enterDrag();
+        }
         return selectionStarted;
     }
 
@@ -2894,7 +2979,6 @@
             }
 
             if (menu.hasVisibleItems() || mode.getCustomView() != null) {
-                getSelectionController().show();
                 mTextView.setHasTransientState(true);
                 return true;
             } else {
@@ -3232,6 +3316,8 @@
         private Runnable mActionPopupShower;
         // Minimum touch target size for handles
         private int mMinSize;
+        // Indicates the line of text that the handle is on.
+        protected int mLine = -1;
 
         public HandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(mTextView.getContext());
@@ -3240,6 +3326,8 @@
             mContainer.setSplitTouchEnabled(true);
             mContainer.setClippingEnabled(false);
             mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+            mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+            mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
             mContainer.setContentView(this);
 
             mDrawableLtr = drawableLtr;
@@ -3407,6 +3495,7 @@
                     addPositionToTouchUpFilter(offset);
                 }
                 final int line = layout.getLineForOffset(offset);
+                mLine = line;
 
                 mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX -
                         getHorizontalOffset() + getCursorOffset());
@@ -3456,6 +3545,30 @@
             }
         }
 
+        public void showAtLocation(int offset) {
+            // TODO - investigate if there's a better way to show the handles
+            // after the drag accelerator has occured.
+            int[] tmpCords = new int[2];
+            mTextView.getLocationInWindow(tmpCords);
+
+            Layout layout = mTextView.getLayout();
+            int posX = tmpCords[0];
+            int posY = tmpCords[1];
+
+            final int line = layout.getLineForOffset(offset);
+
+            int startX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f
+                    - mHotspotX - getHorizontalOffset() + getCursorOffset());
+            int startY = layout.getLineBottom(line);
+
+            // Take TextView's padding and scroll into account.
+            startX += mTextView.viewportToContentHorizontalOffset();
+            startY += mTextView.viewportToContentVerticalOffset();
+
+            mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY,
+                    startX + posX, startY + posY);
+        }
+
         @Override
         protected void onDraw(Canvas c) {
             final int drawWidth = mDrawable.getIntrinsicWidth();
@@ -3694,6 +3807,12 @@
     }
 
     private class SelectionStartHandleView extends HandleView {
+        // The previous offset this handle was at.
+        private int mPrevOffset;
+        // Indicates whether the cursor is making adjustments within a word.
+        private boolean mInWord = false;
+        // Offset to track difference between touch and word boundary.
+        protected int mTouchWordOffset;
 
         public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(drawableLtr, drawableRtl);
@@ -3701,11 +3820,7 @@
 
         @Override
         protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
-            if (isRtlRun) {
-                return drawable.getIntrinsicWidth() / 4;
-            } else {
-                return (drawable.getIntrinsicWidth() * 3) / 4;
-            }
+            return isRtlRun ? 0 : drawable.getIntrinsicWidth();
         }
 
         @Override
@@ -3727,21 +3842,81 @@
 
         @Override
         public void updatePosition(float x, float y) {
-            int offset = mTextView.getOffsetForPosition(x, y);
+            final int trueOffset = mTextView.getOffsetForPosition(x, y);
+            final int currLine = mTextView.getLineAtCoordinate(y);
+            int offset = trueOffset;
+            boolean positionCursor = false;
 
-            // Handles can not cross and selection is at least one character
-            final int selectionEnd = mTextView.getSelectionEnd();
-            if (offset >= selectionEnd) offset = Math.max(0, selectionEnd - 1);
+            int end = getWordEnd(offset, true);
+            int start = getWordStart(offset);
 
-            positionAtCursorOffset(offset, false);
+            if (offset < mPrevOffset) {
+                // User is increasing the selection.
+                if (!mInWord || currLine < mLine) {
+                    // We're not in a word, or we're on a different line so we'll expand by
+                    // word. First ensure the user has at least entered the next word.
+                    int offsetToWord = Math.min((end - start) / 2, 2);
+                    if (offset <= end - offsetToWord || currLine < mLine) {
+                        offset = start;
+                    } else {
+                        offset = mPrevOffset;
+                    }
+                }
+                mPrevOffset = offset;
+                mTouchWordOffset = trueOffset - offset;
+                mInWord = !isStartBoundary(offset);
+                positionCursor = true;
+            } else if (offset - mTouchWordOffset > mPrevOffset) {
+                // User is shrinking the selection.
+                if (currLine > mLine) {
+                    // We're on a different line, so we'll snap to word boundaries.
+                    offset = end;
+                }
+                offset -= mTouchWordOffset;
+                mPrevOffset = offset;
+                mInWord = !isEndBoundary(offset);
+                positionCursor = true;
+            }
+
+            // Handles can not cross and selection is at least one character.
+            if (positionCursor) {
+                final int selectionEnd = mTextView.getSelectionEnd();
+                if (offset >= selectionEnd) {
+                    // We can't cross the handles so let's just constrain the Y value.
+                    int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+                    if (alteredOffset >= selectionEnd) {
+                        // Can't pass the other drag handle.
+                        offset = Math.max(0, selectionEnd - 1);
+                    } else {
+                        offset = alteredOffset;
+                    }
+                }
+                positionAtCursorOffset(offset, false);
+            }
         }
 
         public ActionPopupWindow getActionPopupWindow() {
             return mActionPopupWindow;
         }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            boolean superResult = super.onTouchEvent(event);
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                // Reset the touch word offset when the user has lifted their finger.
+                mTouchWordOffset = 0;
+            }
+            return superResult;
+        }
     }
 
     private class SelectionEndHandleView extends HandleView {
+        // The previous offset this handle was at.
+        private int mPrevOffset;
+        // Indicates whether the cursor is making adjustments within a word.
+        private boolean mInWord = false;
+        // Offset to track difference between touch and word boundary.
+        protected int mTouchWordOffset;
 
         public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(drawableLtr, drawableRtl);
@@ -3749,11 +3924,7 @@
 
         @Override
         protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
-            if (isRtlRun) {
-                return (drawable.getIntrinsicWidth() * 3) / 4;
-            } else {
-                return drawable.getIntrinsicWidth() / 4;
-            }
+            return isRtlRun ? drawable.getIntrinsicWidth() : 0;
         }
 
         @Override
@@ -3775,20 +3946,72 @@
 
         @Override
         public void updatePosition(float x, float y) {
-            int offset = mTextView.getOffsetForPosition(x, y);
+            final int trueOffset = mTextView.getOffsetForPosition(x, y);
+            final int currLine = mTextView.getLineAtCoordinate(y);
+            int offset = trueOffset;
+            boolean positionCursor = false;
 
-            // Handles can not cross and selection is at least one character
-            final int selectionStart = mTextView.getSelectionStart();
-            if (offset <= selectionStart) {
-                offset = Math.min(selectionStart + 1, mTextView.getText().length());
+            int end = getWordEnd(offset, true);
+            int start = getWordStart(offset);
+
+            if (offset > mPrevOffset) {
+                // User is increasing the selection.
+                if (!mInWord || currLine > mLine) {
+                    // We're not in a word, or we're on a different line so we'll expand by
+                    // word. First ensure the user has at least entered the next word.
+                    int midPoint = Math.min((end - start) / 2, 2);
+                    if (offset >= start + midPoint || currLine > mLine) {
+                        offset = end;
+                    } else {
+                        offset = mPrevOffset;
+                    }
+                }
+                mPrevOffset = offset;
+                mTouchWordOffset = offset - trueOffset;
+                mInWord = !isEndBoundary(offset);
+                positionCursor = true;
+            } else if (offset + mTouchWordOffset < mPrevOffset) {
+                // User is shrinking the selection.
+                if (currLine > mLine) {
+                    // We're on a different line, so we'll snap to word boundaries.
+                    offset = getWordStart(offset);
+                }
+                offset += mTouchWordOffset;
+                mPrevOffset = offset;
+                positionCursor = true;
+                mInWord = !isStartBoundary(offset);
             }
 
-            positionAtCursorOffset(offset, false);
+            if (positionCursor) {
+                final int selectionStart = mTextView.getSelectionStart();
+                if (offset <= selectionStart) {
+                    // We can't cross the handles so let's just constrain the Y value.
+                    int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+                    int length = mTextView.getText().length();
+                    if (alteredOffset <= selectionStart) {
+                        // Can't pass the other drag handle.
+                        offset = Math.min(selectionStart + 1, length);
+                    } else {
+                        offset = Math.min(alteredOffset, length);
+                    }
+                }
+                positionAtCursorOffset(offset, false);
+            }
         }
 
         public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
             mActionPopupWindow = actionPopupWindow;
         }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            boolean superResult = super.onTouchEvent(event);
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                // Reset the touch word offset when the user has lifted their finger.
+                mTouchWordOffset = 0;
+            }
+            return superResult;
+        }
     }
 
     /**
@@ -3871,6 +4094,11 @@
         private float mDownPositionX, mDownPositionY;
         private boolean mGestureStayedInTapRegion;
 
+        // Where the user first starts the drag motion.
+        private int mStartOffset = -1;
+        // Indicates whether the user is selecting text and using the drag accelerator.
+        private boolean mDragAcceleratorActive;
+
         SelectionModifierCursorController() {
             resetTouchOffsets();
         }
@@ -3920,6 +4148,22 @@
             if (mEndHandle != null) mEndHandle.hide();
         }
 
+        public void enterDrag() {
+            // Just need to init the handles / hide insertion cursor.
+            show();
+            mDragAcceleratorActive = true;
+            // Start location of selection.
+            mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX,
+                    mLastDownPositionY);
+            // Don't show the handles until user has lifted finger.
+            hide();
+
+            // This stops scrolling parents from intercepting the touch event, allowing
+            // the user to continue dragging across the screen to select text; TextView will
+            // scroll as necessary.
+            mTextView.getParent().requestDisallowInterceptTouchEvent(true);
+        }
+
         public void onTouchEvent(MotionEvent event) {
             // This is done even when the View does not have focus, so that long presses can start
             // selection and tap can move cursor from this tap position.
@@ -3928,7 +4172,7 @@
                     final float x = event.getX();
                     final float y = event.getY();
 
-                    // Remember finger down position, to be able to start selection from there
+                    // Remember finger down position, to be able to start selection from there.
                     mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition(x, y);
 
                     // Double tap detection
@@ -3967,23 +4211,112 @@
                     break;
 
                 case MotionEvent.ACTION_MOVE:
+                    final ViewConfiguration viewConfiguration = ViewConfiguration.get(
+                            mTextView.getContext());
+
                     if (mGestureStayedInTapRegion) {
                         final float deltaX = event.getX() - mDownPositionX;
                         final float deltaY = event.getY() - mDownPositionY;
                         final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
 
-                        final ViewConfiguration viewConfiguration = ViewConfiguration.get(
-                                mTextView.getContext());
                         int doubleTapTouchSlop = viewConfiguration.getScaledDoubleTapTouchSlop();
 
                         if (distanceSquared > doubleTapTouchSlop * doubleTapTouchSlop) {
                             mGestureStayedInTapRegion = false;
                         }
                     }
+
+                    if (mStartHandle != null && mStartHandle.isShowing()) {
+                        // Don't do the drag if the handles are showing already.
+                        break;
+                    }
+
+                    if (mStartOffset != -1) {
+                        final int rawOffset = mTextView.getOffsetForPosition(event.getX(),
+                                event.getY());
+                        int offset = rawOffset;
+
+                        // We don't start "dragging" until the user is past the initial word that
+                        // gets selected on long press.
+                        int firstWordStart = getWordStart(mStartOffset);
+                        int firstWordEnd = getWordEnd(mStartOffset, false);
+                        if (offset > firstWordEnd || offset < firstWordStart) {
+
+                            // Basically the goal in the below code is to have the highlight be
+                            // offset so that your finger isn't covering the end point.
+                            int fingerOffset = viewConfiguration.getScaledTouchSlop();
+                            float mx = event.getX();
+                            float my = event.getY();
+                            if (mx > fingerOffset) mx -= fingerOffset;
+                            if (my > fingerOffset) my -= fingerOffset;
+                            offset = mTextView.getOffsetForPosition(mx, my);
+
+                            // Perform the check for closeness at edge of view, if we're very close
+                            // don't adjust the offset to be in front of the finger - otherwise the
+                            // user can't select words at the edge.
+                            if (mTextView.getWidth() - fingerOffset > mx) {
+                                // We're going by word, so we need to make sure that the offset
+                                // that we get is within this, so we'll get the previous boundary.
+                                final WordIterator wordIterator = getWordIteratorWithText();
+
+                                final int precedingOffset = wordIterator.preceding(offset);
+                                if (mStartOffset < offset) {
+                                    // Expanding with bottom handle, in this case the selection end
+                                    // is before the finger.
+                                    offset = Math.max(precedingOffset - 1, 0);
+                                } else {
+                                    // Expand with the start handle, in this case the selection
+                                    // start is before the finger.
+                                    if (precedingOffset == WordIterator.DONE) {
+                                        offset = 0;
+                                    } else {
+                                        offset = wordIterator.preceding(precedingOffset);
+                                    }
+                                }
+                            }
+                            if (offset == WordIterator.DONE)
+                                offset = rawOffset;
+
+                            // Need to adjust start offset based on direction of movement.
+                            int newStart = mStartOffset < offset ? getWordStart(mStartOffset)
+                                    : getWordEnd(mStartOffset, true);
+                            Selection.setSelection((Spannable) mTextView.getText(), newStart,
+                                    offset);
+                        }
+                    }
                     break;
 
                 case MotionEvent.ACTION_UP:
                     mPreviousTapUpTime = SystemClock.uptimeMillis();
+                    if (mDragAcceleratorActive) {
+                        // No longer dragging to select text, let the parent intercept events.
+                        mTextView.getParent().requestDisallowInterceptTouchEvent(false);
+
+                        show();
+                        int startOffset = mTextView.getSelectionStart();
+                        int endOffset = mTextView.getSelectionEnd();
+
+                        // Since we don't let drag handles pass once they're visible, we need to
+                        // make sure the start / end locations are correct because the user *can*
+                        // switch directions during the initial drag.
+                        if (endOffset < startOffset) {
+                            int tmp = endOffset;
+                            endOffset = startOffset;
+                            startOffset = tmp;
+
+                            // Also update the selection with the right offsets in this case.
+                            Selection.setSelection((Spannable) mTextView.getText(),
+                                    startOffset, endOffset);
+                        }
+
+                        // Need to do this to display the handles.
+                        mStartHandle.showAtLocation(startOffset);
+                        mEndHandle.showAtLocation(endOffset);
+
+                        // No longer the first dragging motion, reset.
+                        mDragAcceleratorActive = false;
+                        mStartOffset = -1;
+                    }
                     break;
             }
         }
@@ -4010,6 +4343,8 @@
 
         public void resetTouchOffsets() {
             mMinTouchOffset = mMaxTouchOffset = -1;
+            mStartOffset = -1;
+            mDragAcceleratorActive = false;
         }
 
         /**
@@ -4019,6 +4354,13 @@
             return mStartHandle != null && mStartHandle.isDragging();
         }
 
+        /**
+         * @return true if the user is selecting text using the drag accelerator.
+         */
+        public boolean isDragAcceleratorActive() {
+            return mDragAcceleratorActive;
+        }
+
         public void onTouchModeChanged(boolean isInTouchMode) {
             if (!isInTouchMode) {
                 hide();
@@ -4217,10 +4559,30 @@
     public static class UndoInputFilter implements InputFilter {
         private final Editor mEditor;
 
+        // Whether the current filter pass is directly caused by an end-user text edit.
+        private boolean mIsUserEdit;
+
+        // Whether this is the first pass through the filter for a given end-user text edit.
+        private boolean mFirstFilterPass;
+
         public UndoInputFilter(Editor editor) {
             mEditor = editor;
         }
 
+        /**
+         * Signals that a user-triggered edit is starting.
+         */
+        public void beginBatchEdit() {
+            if (DEBUG_UNDO) Log.d(TAG, "beginBatchEdit");
+            mIsUserEdit = true;
+            mFirstFilterPass = true;
+        }
+
+        public void endBatchEdit() {
+            if (DEBUG_UNDO) Log.d(TAG, "endBatchEdit");
+            mIsUserEdit = false;
+        }
+
         @Override
         public CharSequence filter(CharSequence source, int start, int end,
                 Spanned dest, int dstart, int dend) {
@@ -4229,36 +4591,24 @@
                         "dest=" + dest + " (" + dstart + "-" + dend + ")");
             }
 
-            if (!mEditor.mAllowUndo) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled");
+            // Check to see if this edit should be tracked for undo.
+            if (!canUndoEdit(source, start, end, dest, dstart, dend)) {
                 return null;
             }
 
-            final UndoManager um = mEditor.mUndoManager;
-            if (um.isInUndo()) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
-                return null;
-            }
-
-            // Text filters run before input operations are applied. However, some input operations
-            // are invalid and will throw exceptions when applied. This is common in tests. Don't
-            // attempt to undo invalid operations.
-            if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
-                return null;
-            }
-
-            // Earlier filters can rewrite input to be a no-op, for example due to a length limit
-            // on an input field. Skip no-op changes.
-            if (start == end && dstart == dend) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
-                return null;
-            }
+            // An application may install a TextWatcher to provide additional modifications after
+            // the initial input filters run (e.g. a credit card formatter that adds spaces to a
+            // string). This results in multiple filter() calls for what the user considers to be
+            // a single operation. Always undo the whole set of changes in one step.
+            final boolean forceMerge = !mFirstFilterPass;
+            mFirstFilterPass = false;
 
             // Build a new operation with all the information from this edit.
-            EditOperation edit = new EditOperation(mEditor, source, start, end, dest, dstart, dend);
+            EditOperation edit = new EditOperation(mEditor, forceMerge,
+                    source, start, end, dest, dstart, dend);
 
             // Fetch the last edit operation and attempt to merge in the new edit.
+            final UndoManager um = mEditor.mUndoManager;
             um.beginUpdate("Edit text");
             EditOperation lastEdit = um.getLastOperation(
                   EditOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
@@ -4266,6 +4616,12 @@
                 // Add this as the first edit.
                 if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
                 um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+            } else if (!mIsUserEdit) {
+                // An application directly modified the Editable outside of a text edit. Treat this
+                // as a new change and don't attempt to merge.
+                if (DEBUG_UNDO) Log.d(TAG, "non-user edit, new op " + edit);
+                um.commitState(mEditor.mUndoOwner);
+                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
             } else if (lastEdit.mergeWith(edit)) {
                 // Merge succeeded, nothing else to do.
                 if (DEBUG_UNDO) Log.d(TAG, "filter: merge succeeded, created " + lastEdit);
@@ -4278,6 +4634,36 @@
             um.endUpdate();
             return null;  // Text not changed.
         }
+
+        private boolean canUndoEdit(CharSequence source, int start, int end,
+                Spanned dest, int dstart, int dend) {
+            if (!mEditor.mAllowUndo) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled");
+                return false;
+            }
+
+            if (mEditor.mUndoManager.isInUndo()) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
+                return false;
+            }
+
+            // Text filters run before input operations are applied. However, some input operations
+            // are invalid and will throw exceptions when applied. This is common in tests. Don't
+            // attempt to undo invalid operations.
+            if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
+                return false;
+            }
+
+            // Earlier filters can rewrite input to be a no-op, for example due to a length limit
+            // on an input field. Skip no-op changes.
+            if (start == end && dstart == dend) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
+                return false;
+            }
+
+            return true;
+        }
     }
 
     /**
@@ -4289,6 +4675,7 @@
         private static final int TYPE_REPLACE = 2;
 
         private int mType;
+        private boolean mForceMerge;
         private String mOldText;
         private int mOldTextStart;
         private String mNewText;
@@ -4300,10 +4687,12 @@
         /**
          * Constructs an edit operation from a text input operation that replaces the range
          * (dstart, dend) of dest with (start, end) of source. See {@link InputFilter#filter}.
+         * If forceMerge is true then always forcibly merge this operation with any previous one.
          */
-        public EditOperation(Editor editor, CharSequence source, int start, int end,
-                Spanned dest, int dstart, int dend) {
+        public EditOperation(Editor editor, boolean forceMerge,
+                CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
             super(editor.mUndoOwner);
+            mForceMerge = forceMerge;
 
             mOldText = dest.subSequence(dstart, dend).toString();
             mNewText = source.subSequence(start, end).toString();
@@ -4331,6 +4720,7 @@
         public EditOperation(Parcel src, ClassLoader loader) {
             super(src, loader);
             mType = src.readInt();
+            mForceMerge = src.readInt() != 0;
             mOldText = src.readString();
             mOldTextStart = src.readInt();
             mNewText = src.readString();
@@ -4342,6 +4732,7 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mType);
+            dest.writeInt(mForceMerge ? 1 : 0);
             dest.writeString(mOldText);
             dest.writeInt(mOldTextStart);
             dest.writeString(mNewText);
@@ -4350,6 +4741,14 @@
             dest.writeInt(mNewCursorPos);
         }
 
+        private int getNewTextEnd() {
+            return mNewTextStart + mNewText.length();
+        }
+
+        private int getOldTextEnd() {
+            return mOldTextStart + mOldText.length();
+        }
+
         @Override
         public void commit() {
         }
@@ -4358,14 +4757,20 @@
         public void undo() {
             if (DEBUG_UNDO) Log.d(TAG, "undo");
             // Remove the new text and insert the old.
-            modifyText(mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, mOldCursorPos);
+            Editor editor = getOwnerData();
+            Editable text = (Editable) editor.mTextView.getText();
+            modifyText(text, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+                    mOldCursorPos);
         }
 
         @Override
         public void redo() {
             if (DEBUG_UNDO) Log.d(TAG, "redo");
             // Remove the old text and insert the new.
-            modifyText(mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart, mNewCursorPos);
+            Editor editor = getOwnerData();
+            Editable text = (Editable) editor.mTextView.getText();
+            modifyText(text, mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart,
+                    mNewCursorPos);
         }
 
         /**
@@ -4375,6 +4780,14 @@
          * object unchanged.
          */
         private boolean mergeWith(EditOperation edit) {
+            if (DEBUG_UNDO) {
+                Log.d(TAG, "mergeWith old " + this);
+                Log.d(TAG, "mergeWith new " + edit);
+            }
+            if (edit.mForceMerge) {
+                forceMergeWith(edit);
+                return true;
+            }
             switch (mType) {
                 case TYPE_INSERT:
                     return mergeInsertWith(edit);
@@ -4388,7 +4801,6 @@
         }
 
         private boolean mergeInsertWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeInsertWith " + edit);
             // Only merge continuous insertions.
             if (edit.mType != TYPE_INSERT) {
                 return false;
@@ -4404,7 +4816,6 @@
 
         // TODO: Support forward delete.
         private boolean mergeDeleteWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeDeleteWith " + edit);
             // Only merge continuous deletes.
             if (edit.mType != TYPE_DELETE) {
                 return false;
@@ -4420,11 +4831,8 @@
         }
 
         private boolean mergeReplaceWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeReplaceWith " + edit);
-            // Replacements can merge only with adjacent inserts and adjacent replacements.
-            if (edit.mType == TYPE_DELETE ||
-                    getNewTextEnd() != edit.mOldTextStart ||
-                    edit.mOldTextStart != edit.mNewTextStart) {
+            // Replacements can merge only with adjacent inserts.
+            if (edit.mType != TYPE_INSERT || getNewTextEnd() != edit.mNewTextStart) {
                 return false;
             }
             mOldText += edit.mOldText;
@@ -4433,18 +4841,42 @@
             return true;
         }
 
-        private int getNewTextEnd() {
-            return mNewTextStart + mNewText.length();
-        }
-
-        private int getOldTextEnd() {
-            return mOldTextStart + mOldText.length();
-        }
-
-        private void modifyText(int deleteFrom, int deleteTo, CharSequence newText,
-                int newTextInsertAt, int newCursorPos) {
+        /**
+         * Forcibly creates a single merged edit operation by simulating the entire text
+         * contents being replaced.
+         */
+        private void forceMergeWith(EditOperation edit) {
+            if (DEBUG_UNDO) Log.d(TAG, "forceMerge");
             Editor editor = getOwnerData();
-            Editable text = (Editable) editor.mTextView.getText();
+
+            // Copy the text of the current field.
+            // NOTE: Using StringBuilder instead of SpannableStringBuilder would be somewhat faster,
+            // but would require two parallel implementations of modifyText() because Editable and
+            // StringBuilder do not share an interface for replace/delete/insert.
+            Editable editable = (Editable) editor.mTextView.getText();
+            Editable originalText = new SpannableStringBuilder(editable.toString());
+
+            // Roll back the last operation.
+            modifyText(originalText, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+                    mOldCursorPos);
+
+            // Clone the text again and apply the new operation.
+            Editable finalText = new SpannableStringBuilder(editable.toString());
+            modifyText(finalText, edit.mOldTextStart, edit.getOldTextEnd(), edit.mNewText,
+                    edit.mNewTextStart, edit.mNewCursorPos);
+
+            // Convert this operation into a non-mergeable replacement of the entire string.
+            mType = TYPE_REPLACE;
+            mNewText = finalText.toString();
+            mNewTextStart = 0;
+            mOldText = originalText.toString();
+            mOldTextStart = 0;
+            mNewCursorPos = edit.mNewCursorPos;
+            // mOldCursorPos is unchanged.
+        }
+
+        private static void modifyText(Editable text, int deleteFrom, int deleteTo,
+                CharSequence newText, int newTextInsertAt, int newCursorPos) {
             // Apply the edit if it is still valid.
             if (isValidRange(text, deleteFrom, deleteTo) &&
                     newTextInsertAt <= text.length() - (deleteTo - deleteFrom)) {
@@ -4455,17 +4887,30 @@
                     text.insert(newTextInsertAt, newText);
                 }
             }
-            // Restore the cursor position.
+            // Restore the cursor position. If there wasn't an old cursor (newCursorPos == -1) then
+            // don't explicitly set it and rely on SpannableStringBuilder to position it.
             // TODO: Select all the text that was undone.
-            if (newCursorPos <= text.length()) {
+            if (0 <= newCursorPos && newCursorPos <= text.length()) {
                 Selection.setSelection(text, newCursorPos);
             }
         }
 
+        private String getTypeString() {
+            switch (mType) {
+                case TYPE_INSERT:
+                    return "insert";
+                case TYPE_DELETE:
+                    return "delete";
+                case TYPE_REPLACE:
+                    return "replace";
+                default:
+                    return "";
+            }
+        }
+
         @Override
         public String toString() {
-            return "EditOperation: [" +
-                    "mType=" + mType + ", " +
+            return "[mType=" + getTypeString() + ", " +
                     "mOldText=" + mOldText + ", " +
                     "mOldTextStart=" + mOldTextStart + ", " +
                     "mNewText=" + mNewText + ", " +
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index e8dc11f..f6d198b 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -101,15 +101,16 @@
         super(context);
     }
     
-    public FrameLayout(Context context, AttributeSet attrs) {
+    public FrameLayout(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+    public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public FrameLayout(
+            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index e8fe191..6cc4bda 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -141,7 +141,9 @@
  * view was alone in a column, that column would itself collapse to zero width if and only if
  * no gravity was defined on the view. If gravity was defined, then the gone-marked
  * view has no effect on the layout and the container should be laid out as if the view
- * had never been added to it.
+ * had never been added to it. GONE views are taken to have zero weight during excess space
+ * distribution.
+ * <p>
  * These statements apply equally to rows as well as columns, and to groups of rows or columns.
  *
  * <p>
@@ -1010,12 +1012,10 @@
             LayoutParams lp = getLayoutParams(c);
             if (firstPass) {
                 measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
-                mHorizontalAxis.recordOriginalMeasurement(i);
-                mVerticalAxis.recordOriginalMeasurement(i);
             } else {
                 boolean horizontal = (mOrientation == HORIZONTAL);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                if (spec.alignment == FILL) {
+                if (spec.getAbsoluteAlignment(horizontal) == FILL) {
                     Interval span = spec.span;
                     Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
                     int[] locations = axis.getLocations();
@@ -1091,11 +1091,6 @@
         invalidateValues();
     }
 
-    final Alignment getAlignment(Alignment alignment, boolean horizontal) {
-        return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
-                (horizontal ? START : BASELINE);
-    }
-
     // Layout container
 
     /**
@@ -1150,8 +1145,8 @@
             int pWidth = getMeasurement(c, true);
             int pHeight = getMeasurement(c, false);
 
-            Alignment hAlign = getAlignment(columnSpec.alignment, true);
-            Alignment vAlign = getAlignment(rowSpec.alignment, false);
+            Alignment hAlign = columnSpec.getAbsoluteAlignment(true);
+            Alignment vAlign = rowSpec.getAbsoluteAlignment(false);
 
             Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
             Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
@@ -1234,7 +1229,6 @@
 
         public boolean hasWeights;
         public boolean hasWeightsValid = false;
-        public int[] originalMeasurements;
         public int[] deltas;
 
         boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
@@ -1297,7 +1291,7 @@
                 // we must include views that are GONE here, see introductory javadoc
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
+                Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds();
                 assoc.put(spec, bounds);
             }
             return assoc.pack();
@@ -1313,9 +1307,8 @@
                 // we must include views that are GONE here, see introductory javadoc
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                int size = (spec.weight == 0) ?
-                        getMeasurementIncludingMargin(c, horizontal) :
-                        getOriginalMeasurements()[i] + getDeltas()[i];
+                int size = getMeasurementIncludingMargin(c, horizontal) +
+                        ((spec.weight == 0) ? 0 : getDeltas()[i]);
                 groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size);
             }
         }
@@ -1703,7 +1696,11 @@
 
         private boolean computeHasWeights() {
             for (int i = 0, N = getChildCount(); i < N; i++) {
-                LayoutParams lp = getLayoutParams(getChildAt(i));
+                final View child = getChildAt(i);
+                if (child.getVisibility() == View.GONE) {
+                    continue;
+                }
+                LayoutParams lp = getLayoutParams(child);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 if (spec.weight != 0) {
                     return true;
@@ -1720,19 +1717,6 @@
             return hasWeights;
         }
 
-        public int[] getOriginalMeasurements() {
-            if (originalMeasurements == null) {
-                originalMeasurements = new int[getChildCount()];
-            }
-            return originalMeasurements;
-        }
-
-        private void recordOriginalMeasurement(int i) {
-            if (hasWeights()) {
-                getOriginalMeasurements()[i] = getMeasurementIncludingMargin(getChildAt(i), horizontal);
-            }
-        }
-
         public int[] getDeltas() {
             if (deltas == null) {
                 deltas = new int[getChildCount()];
@@ -1743,7 +1727,10 @@
         private void shareOutDelta(int totalDelta, float totalWeight) {
             Arrays.fill(deltas, 0);
             for (int i = 0, N = getChildCount(); i < N; i++) {
-                View c = getChildAt(i);
+                final View c = getChildAt(i);
+                if (c.getVisibility() == View.GONE) {
+                    continue;
+                }
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 float weight = spec.weight;
@@ -1796,6 +1783,9 @@
             float totalWeight = 0f;
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
+                if (c.getVisibility() == View.GONE) {
+                    continue;
+                }
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 totalWeight += spec.weight;
@@ -1891,7 +1881,6 @@
 
             locations = null;
 
-            originalMeasurements = null;
             deltas = null;
             hasWeightsValid = false;
 
@@ -2011,7 +2000,6 @@
                 R.styleable.ViewGroup_MarginLayout_layout_marginRight;
         private static final int BOTTOM_MARGIN =
                 R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
-
         private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
         private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
         private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
@@ -2405,7 +2393,7 @@
         protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) {
             this.flexibility &= spec.getFlexibility();
             boolean horizontal = axis.horizontal;
-            Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
+            Alignment alignment = spec.getAbsoluteAlignment(axis.horizontal);
             // todo test this works correctly when the returned value is UNDEFINED
             int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
             include(before, size - before);
@@ -2556,6 +2544,16 @@
             this(startDefined, new Interval(start, start + size), alignment, weight);
         }
 
+        private Alignment getAbsoluteAlignment(boolean horizontal) {
+            if (alignment != UNDEFINED_ALIGNMENT) {
+                return alignment;
+            }
+            if (weight == 0f) {
+                return horizontal ? START : BASELINE;
+            }
+            return FILL;
+        }
+
         final Spec copyWriteSpan(Interval span) {
             return new Spec(startDefined, span, alignment, weight);
         }
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index f599035..da15302 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -186,11 +187,11 @@
         this(context, null);
     }
 
-    public LinearLayout(Context context, AttributeSet attrs) {
+    public LinearLayout(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
     
-    public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+    public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index a224f5e..d12739f 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -515,6 +515,23 @@
             }
         }
 
+        // Use the top-start-most laid out view as the baseline. RTL offsets are
+        // applied later, so we can use the left-most edge as the starting edge.
+        View baselineView = null;
+        LayoutParams baselineParams = null;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams childParams = (LayoutParams) child.getLayoutParams();
+                if (baselineView == null || baselineParams == null
+                        || compareLayoutPosition(childParams, baselineParams) < 0) {
+                    baselineView = child;
+                    baselineParams = childParams;
+                }
+            }
+        }
+        mBaselineView = baselineView;
+
         if (isWrapContentWidth) {
             // Width already has left padding in it since it was calculated by looking at
             // the right of each child view
@@ -616,25 +633,24 @@
             }
         }
 
-        // Use the bottom-most laid out view as the baseline.
-        View baselineView = null;
-        int baseline = 0;
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                final int childBaseline = child.getBaseline();
-                if (childBaseline >= baseline) {
-                    baselineView = child;
-                    baseline = childBaseline;
-                }
-            }
-        }
-        mBaselineView = baselineView;
-
         setMeasuredDimension(width, height);
     }
 
     /**
+     * @return a negative number if the top of {@code p1} is above the top of
+     *         {@code p2} or if they have identical top values and the left of
+     *         {@code p1} is to the left of {@code p2}, or a positive number
+     *         otherwise
+     */
+    private int compareLayoutPosition(LayoutParams p1, LayoutParams p2) {
+        final int topDiff = p1.mTop - p2.mTop;
+        if (topDiff != 0) {
+            return topDiff;
+        }
+        return p1.mLeft - p2.mLeft;
+    }
+
+    /**
      * Measure a child. The child should have left, top, right and bottom information
      * stored in its LayoutParams. If any of these values is VALUE_NOT_SET it means
      * that the view can extend up to the corresponding edge.
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dd7fa18..a10be11 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -2263,7 +2264,7 @@
      * @param color Sets the text color for all the states (normal, selected,
      *            focused) to be this color.
      */
-    public void setTextColor(int viewId, int color) {
+    public void setTextColor(int viewId, @ColorInt int color) {
         setInt(viewId, "setTextColor", color);
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 632f5c7..faf1c40 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.R;
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -637,16 +638,17 @@
         this(context, null);
     }
 
-    public TextView(Context context, AttributeSet attrs) {
+    public TextView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.textViewStyle);
     }
 
-    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
     @SuppressWarnings("deprecation")
-    public TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public TextView(
+            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         mText = "";
@@ -2996,7 +2998,7 @@
      * @attr ref android.R.styleable#TextView_textColor
      */
     @android.view.RemotableViewMethod
-    public void setTextColor(int color) {
+    public void setTextColor(@ColorInt int color) {
         mTextColor = ColorStateList.valueOf(color);
         updateTextColors();
     }
@@ -3037,6 +3039,7 @@
      *
      * @return Returns the current text color.
      */
+    @ColorInt
     public final int getCurrentTextColor() {
         return mCurTextColor;
     }
@@ -3047,7 +3050,7 @@
      * @attr ref android.R.styleable#TextView_textColorHighlight
      */
     @android.view.RemotableViewMethod
-    public void setHighlightColor(int color) {
+    public void setHighlightColor(@ColorInt int color) {
         if (mHighlightColor != color) {
             mHighlightColor = color;
             invalidate();
@@ -3061,6 +3064,7 @@
      *
      * @attr ref android.R.styleable#TextView_textColorHighlight
      */
+    @ColorInt
     public int getHighlightColor() {
         return mHighlightColor;
     }
@@ -3155,6 +3159,7 @@
      *
      * @attr ref android.R.styleable#TextView_shadowColor
      */
+    @ColorInt
     public int getShadowColor() {
         return mShadowColor;
     }
@@ -3230,7 +3235,7 @@
      * @attr ref android.R.styleable#TextView_textColorHint
      */
     @android.view.RemotableViewMethod
-    public final void setHintTextColor(int color) {
+    public final void setHintTextColor(@ColorInt int color) {
         mHintTextColor = ColorStateList.valueOf(color);
         updateTextColors();
     }
@@ -3269,6 +3274,7 @@
      *
      * @return Returns the current hint text color.
      */
+    @ColorInt
     public final int getCurrentHintTextColor() {
         return mHintTextColor != null ? mCurHintTextColor : mCurTextColor;
     }
@@ -3282,7 +3288,7 @@
      * @attr ref android.R.styleable#TextView_textColorLink
      */
     @android.view.RemotableViewMethod
-    public final void setLinkTextColor(int color) {
+    public final void setLinkTextColor(@ColorInt int color) {
         mLinkTextColor = ColorStateList.valueOf(color);
         updateTextColors();
     }
@@ -4119,6 +4125,7 @@
         if (type == BufferType.EDITABLE || getKeyListener() != null ||
                 needEditableForNotification) {
             createEditorIfNeeded();
+            mEditor.forgetUndoRedo();
             Editable t = mEditableFactory.newEditable(text);
             text = t;
             setFilters(t, mFilters);
@@ -8098,7 +8105,14 @@
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
 
-        if (mEditor != null) mEditor.onTouchEvent(event);
+        if (mEditor != null) {
+            mEditor.onTouchEvent(event);
+
+            if (mEditor.mSelectionModifierCursorController != null &&
+                    mEditor.mSelectionModifierCursorController.isDragAcceleratorActive()) {
+                return true;
+            }
+        }
 
         final boolean superResult = super.onTouchEvent(event);
 
@@ -9104,7 +9118,7 @@
         return getLayout().getLineForVertical((int) y);
     }
 
-    private int getOffsetAtCoordinate(int line, float x) {
+    int getOffsetAtCoordinate(int line, float x) {
         x = convertToLocalHorizontalCoordinate(x);
         return getLayout().getOffsetForHorizontal(line, x);
     }
@@ -9726,4 +9740,4 @@
             TextView.this.spanChange(buf, what, s, -1, e, -1);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 9bc2aab..d2430bc 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActionBar;
@@ -685,7 +686,7 @@
      *
      * @param color The new text color in 0xAARRGGBB format
      */
-    public void setTitleTextColor(int color) {
+    public void setTitleTextColor(@ColorInt int color) {
         mTitleTextColor = color;
         if (mTitleTextView != null) {
             mTitleTextView.setTextColor(color);
@@ -697,7 +698,7 @@
      *
      * @param color The new text color in 0xAARRGGBB format
      */
-    public void setSubtitleTextColor(int color) {
+    public void setSubtitleTextColor(@ColorInt int color) {
         mSubtitleTextColor = color;
         if (mSubtitleTextView != null) {
             mSubtitleTextView.setTextColor(color);
diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java
new file mode 100644
index 0000000..7e70b0c
--- /dev/null
+++ b/core/java/com/android/internal/app/DumpHeapActivity.java
@@ -0,0 +1,106 @@
+/*
+ * 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.app;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ClipData;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.DebugUtils;
+
+/**
+ * This activity is displayed when the system has collected a heap dump from
+ * a large process and the user has selected to share it.
+ */
+public class DumpHeapActivity extends Activity {
+    /** The process we are reporting */
+    public static final String KEY_PROCESS = "process";
+    /** The size limit the process reached */
+    public static final String KEY_SIZE = "size";
+
+    // Broadcast action to determine when to delete the current dump heap data.
+    public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP";
+
+    // Extra for above: delay delete of data, since the user is in the process of sharing it.
+    public static final String EXTRA_DELAY_DELETE = "delay_delete";
+
+    static final public Uri JAVA_URI = Uri.parse("content://com.android.server.heapdump/java");
+
+    String mProcess;
+    long mSize;
+    AlertDialog mDialog;
+    boolean mHandled = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mProcess = getIntent().getStringExtra(KEY_PROCESS);
+        mSize = getIntent().getLongExtra(KEY_SIZE, 0);
+        AlertDialog.Builder b = new AlertDialog.Builder(this,
+                android.R.style.Theme_Material_Light_Dialog_Alert);
+        b.setTitle(com.android.internal.R.string.dump_heap_title);
+        b.setMessage(getString(com.android.internal.R.string.dump_heap_text,
+                mProcess, DebugUtils.sizeValueToString(mSize, null)));
+        b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                mHandled = true;
+                sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
+                finish();
+            }
+        });
+        b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                mHandled = true;
+                Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
+                broadcast.putExtra(EXTRA_DELAY_DELETE, true);
+                sendBroadcast(broadcast);
+                Intent intent = new Intent(Intent.ACTION_SEND);
+                ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
+                intent.setClipData(clip);
+                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                intent.setType(clip.getDescription().getMimeType(0));
+                intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI);
+                startActivity(Intent.createChooser(intent,
+                        getText(com.android.internal.R.string.dump_heap_title)));
+                finish();
+        }
+        });
+        mDialog = b.show();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (!isChangingConfigurations()) {
+            if (!mHandled) {
+                sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
+            }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mDialog.dismiss();
+    }
+}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 70fb510..75beee9 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -24,6 +24,7 @@
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -897,17 +898,17 @@
                         pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
                         pw.print(count);
                         pw.print(" samples ");
-                        printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
                         pw.print(" / ");
-                        printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
                         pw.println();
                     }
                 }
@@ -924,9 +925,9 @@
         if (proc.mNumCachedKill != 0) {
             pw.print(prefix); pw.print("Killed from cached state: ");
                     pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
-                    printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
-                    printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
-                    printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
+                    DebugUtils.printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
+                    DebugUtils.printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
+                    DebugUtils.printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
         }
     }
 
@@ -939,11 +940,11 @@
             int bucket, int index) {
         pw.print(prefix); pw.print(label);
         pw.print(": ");
-        printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
+        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
         pw.print(" min, ");
-        printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
+        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
         pw.print(" avg, ");
-        printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
+        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
         pw.println(" max");
     }
 
@@ -1150,43 +1151,6 @@
         pw.print("%");
     }
 
-    static void printSizeValue(PrintWriter pw, long number) {
-        float result = number;
-        String suffix = "";
-        if (result > 900) {
-            suffix = "KB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "MB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "GB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "TB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "PB";
-            result = result / 1024;
-        }
-        String value;
-        if (result < 1) {
-            value = String.format("%.2f", result);
-        } else if (result < 10) {
-            value = String.format("%.1f", result);
-        } else if (result < 100) {
-            value = String.format("%.0f", result);
-        } else {
-            value = String.format("%.0f", result);
-        }
-        pw.print(value);
-        pw.print(suffix);
-    }
-
     public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
             boolean sepProcStates, int[] procStates, long now) {
@@ -2437,7 +2401,7 @@
             pw.print(prefix);
             pw.print(label);
             pw.print(": ");
-            printSizeValue(pw, mem);
+            DebugUtils.printSizeValue(pw, mem);
             pw.print(" (");
             pw.print(samples);
             pw.print(" samples)");
@@ -2475,7 +2439,7 @@
         totalPss = printMemoryCategory(pw, "  ", "Z-Ram  ", totalMem.sysMemZRamWeight,
                 totalMem.totalTime, totalPss, totalMem.sysMemSamples);
         pw.print("  TOTAL  : ");
-        printSizeValue(pw, totalPss);
+        DebugUtils.printSizeValue(pw, totalPss);
         pw.println();
         printMemoryCategory(pw, "  ", STATE_NAMES[STATE_SERVICE_RESTARTING],
                 totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
@@ -3781,17 +3745,17 @@
             printPercent(pw, (double) totalTime / (double) overallTime);
             if (numPss > 0) {
                 pw.print(" (");
-                printSizeValue(pw, minPss * 1024);
+                DebugUtils.printSizeValue(pw, minPss * 1024);
                 pw.print("-");
-                printSizeValue(pw, avgPss * 1024);
+                DebugUtils.printSizeValue(pw, avgPss * 1024);
                 pw.print("-");
-                printSizeValue(pw, maxPss * 1024);
+                DebugUtils.printSizeValue(pw, maxPss * 1024);
                 pw.print("/");
-                printSizeValue(pw, minUss * 1024);
+                DebugUtils.printSizeValue(pw, minUss * 1024);
                 pw.print("-");
-                printSizeValue(pw, avgUss * 1024);
+                DebugUtils.printSizeValue(pw, avgUss * 1024);
                 pw.print("-");
-                printSizeValue(pw, maxUss * 1024);
+                DebugUtils.printSizeValue(pw, maxUss * 1024);
                 if (full) {
                     pw.print(" over ");
                     pw.print(numPss);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index a410e45..3ceea9d 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -342,6 +342,9 @@
                         return;
                     }
 
+                    // Do not show the profile switch message anymore.
+                    mProfileSwitchMessageId = -1;
+
                     final Intent intent = intentForDisplayResolveInfo(dri);
                     onIntentSelected(dri.ri, intent, false);
                     finish();
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index c3cc60a..fb0ffb0 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -369,6 +369,9 @@
                 return TRANSPORT_ERROR;
             }
         }
+        if (DEBUG) {
+            Log.v(TAG, "   stored " + numBytes + " of data");
+        }
         return TRANSPORT_OK;
     }
 
@@ -431,6 +434,10 @@
 
     @Override
     public RestoreDescription nextRestorePackage() {
+        if (DEBUG) {
+            Log.v(TAG, "nextRestorePackage() : mRestorePackage=" + mRestorePackage
+                    + " length=" + mRestorePackages.length);
+        }
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
 
         boolean found = false;
@@ -441,7 +448,10 @@
             // skip packages where we have a data dir but no actual contents
             String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
             if (contents != null && contents.length > 0) {
-                if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) = " + name);
+                if (DEBUG) {
+                    Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) @ "
+                        + mRestorePackage + " = " + name);
+                }
                 mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
                 found = true;
             }
@@ -450,7 +460,10 @@
                 // No key/value data; check for [non-empty] full data
                 File maybeFullData = new File(mRestoreSetFullDir, name);
                 if (maybeFullData.length() > 0) {
-                    if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) = " + name);
+                    if (DEBUG) {
+                        Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) @ "
+                                + mRestorePackage + " = " + name);
+                    }
                     mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
                     mCurFullRestoreStream = null;   // ensure starting from the ground state
                     found = true;
@@ -460,6 +473,11 @@
             if (found) {
                 return new RestoreDescription(name, mRestoreType);
             }
+
+            if (DEBUG) {
+                Log.v(TAG, "  ... package @ " + mRestorePackage + " = " + name
+                        + " has no data; skipping");
+            }
         }
 
         if (DEBUG) Log.v(TAG, "  no more packages to restore");
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index cfeca08..4cd959f 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -26,12 +26,15 @@
     public double value;
     public double[] values;
     public DrainType drainType;
+
+    // Measured in milliseconds.
     public long usageTime;
     public long cpuTime;
     public long gpsTime;
     public long wifiRunningTime;
     public long cpuFgTime;
     public long wakeLockTime;
+
     public long mobileRxPackets;
     public long mobileTxPackets;
     public long mobileActive;
@@ -48,6 +51,14 @@
     public String[] mPackages;
     public String packageWithHighestDrain;
 
+    // Measured in mAh (milli-ampere per hour).
+    public double wifiPower;
+    public double cpuPower;
+    public double wakeLockPower;
+    public double mobileRadioPower;
+    public double gpsPower;
+    public double sensorPower;
+
     public enum DrainType {
         IDLE,
         CELL,
@@ -107,4 +118,31 @@
         }
         return uidObj.getUid();
     }
+
+    /**
+     * Add stats from other to this BatterySipper.
+     */
+    public void add(BatterySipper other) {
+        cpuTime += other.cpuTime;
+        gpsTime += other.gpsTime;
+        wifiRunningTime += other.wifiRunningTime;
+        cpuFgTime += other.cpuFgTime;
+        wakeLockTime += other.wakeLockTime;
+        mobileRxPackets += other.mobileRxPackets;
+        mobileTxPackets += other.mobileTxPackets;
+        mobileActive += other.mobileActive;
+        mobileActiveCount += other.mobileActiveCount;
+        wifiRxPackets += other.wifiRxPackets;
+        wifiTxPackets += other.wifiTxPackets;
+        mobileRxBytes += other.mobileRxBytes;
+        mobileTxBytes += other.mobileTxBytes;
+        wifiRxBytes += other.wifiRxBytes;
+        wifiTxBytes += other.wifiTxBytes;
+        wifiPower += other.wifiPower;
+        gpsPower += other.gpsPower;
+        cpuPower += other.cpuPower;
+        sensorPower += other.sensorPower;
+        mobileRadioPower += other.mobileRadioPower;
+        wakeLockPower += other.wakeLockPower;
+    }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index eae4427..d3611bf 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -344,6 +344,7 @@
                 mMobilemsppList.add(bs);
             }
         }
+
         for (int i=0; i<mUserSippers.size(); i++) {
             List<BatterySipper> user = mUserSippers.valueAt(i);
             for (int j=0; j<user.size(); j++) {
@@ -389,8 +390,8 @@
 
     private void processAppUsage(SparseArray<UserHandle> asUsers) {
         final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
-        SensorManager sensorManager = (SensorManager) mContext.getSystemService(
-                Context.SENSOR_SERVICE);
+        final SensorManager sensorManager =
+                (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
         final int which = mStatsType;
         final int speedSteps = mPowerProfile.getNumSpeedSteps();
         final double[] powerCpuNormal = new double[speedSteps];
@@ -401,238 +402,317 @@
         final double mobilePowerPerPacket = getMobilePowerPerPacket();
         final double mobilePowerPerMs = getMobilePowerPerMs();
         final double wifiPowerPerPacket = getWifiPowerPerPacket();
-        long appWakelockTimeUs = 0;
+        long totalAppWakelockTimeUs = 0;
         BatterySipper osApp = null;
         mStatsPeriod = mTypeBatteryRealtime;
-        SparseArray<? extends Uid> uidStats = mStats.getUidStats();
+
+        final ArrayList<BatterySipper> appList = new ArrayList<>();
+
+        // Max values used to normalize later.
+        double maxWifiPower = 0;
+        double maxCpuPower = 0;
+        double maxWakeLockPower = 0;
+        double maxMobileRadioPower = 0;
+        double maxGpsPower = 0;
+        double maxSensorPower = 0;
+
+        final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
         final int NU = uidStats.size();
         for (int iu = 0; iu < NU; iu++) {
-            Uid u = uidStats.valueAt(iu);
-            double p; // in mAs
-            double power = 0; // in mAs
-            double highestDrain = 0;
-            String packageWithHighestDrain = null;
-            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
-            long cpuTime = 0;
-            long cpuFgTime = 0;
-            long wakelockTime = 0;
-            long gpsTime = 0;
+            final Uid u = uidStats.valueAt(iu);
+            final BatterySipper app = new BatterySipper(
+                    BatterySipper.DrainType.APP, u, new double[]{0});
+
+            final Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
             if (processStats.size() > 0) {
-                // Process CPU time
+                // Process CPU time.
+
+                // Keep track of the package with highest drain.
+                double highestDrain = 0;
+
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
                         : processStats.entrySet()) {
                     Uid.Proc ps = ent.getValue();
-                    final long userTime = ps.getUserTime(which);
-                    final long systemTime = ps.getSystemTime(which);
-                    final long foregroundTime = ps.getForegroundTime(which);
-                    cpuFgTime += foregroundTime * 10; // convert to millis
-                    final long tmpCpuTime = (userTime + systemTime) * 10; // convert to millis
-                    int totalTimeAtSpeeds = 0;
-                    // Get the total first
+                    app.cpuFgTime += ps.getForegroundTime(which);
+                    final long totalCpuTime = ps.getUserTime(which) + ps.getSystemTime(which);
+                    app.cpuTime += totalCpuTime;
+
+                    // Calculate the total CPU time spent at the various speed steps.
+                    long totalTimeAtSpeeds = 0;
                     for (int step = 0; step < speedSteps; step++) {
                         cpuSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, which);
                         totalTimeAtSpeeds += cpuSpeedStepTimes[step];
                     }
-                    if (totalTimeAtSpeeds == 0) totalTimeAtSpeeds = 1;
-                    // Then compute the ratio of time spent at each speed
-                    double processPower = 0;
+                    totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
+
+                    // Then compute the ratio of time spent at each speed and figure out
+                    // the total power consumption.
+                    double cpuPower = 0;
                     for (int step = 0; step < speedSteps; step++) {
-                        double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds;
-                        if (DEBUG && ratio != 0) Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
-                                + step + " ratio=" + makemAh(ratio) + " power="
-                                + makemAh(ratio*tmpCpuTime*powerCpuNormal[step] / (60*60*1000)));
-                        processPower += ratio * tmpCpuTime * powerCpuNormal[step];
+                        final double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds;
+                        final double cpuSpeedStepPower =
+                                ratio * totalCpuTime * powerCpuNormal[step];
+                        if (DEBUG && ratio != 0) {
+                            Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
+                                    + step + " ratio=" + makemAh(ratio) + " power="
+                                    + makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
+                        }
+                        cpuPower += cpuSpeedStepPower;
                     }
-                    cpuTime += tmpCpuTime;
-                    if (DEBUG && processPower != 0) {
+
+                    if (DEBUG && cpuPower != 0) {
                         Log.d(TAG, String.format("process %s, cpu power=%s",
-                                ent.getKey(), makemAh(processPower / (60*60*1000))));
+                                ent.getKey(), makemAh(cpuPower / (60 * 60 * 1000))));
                     }
-                    power += processPower;
-                    if (packageWithHighestDrain == null
-                            || packageWithHighestDrain.startsWith("*")) {
-                        highestDrain = processPower;
-                        packageWithHighestDrain = ent.getKey();
-                    } else if (highestDrain < processPower
-                            && !ent.getKey().startsWith("*")) {
-                        highestDrain = processPower;
-                        packageWithHighestDrain = ent.getKey();
+                    app.cpuPower += cpuPower;
+
+                    // Each App can have multiple packages and with multiple running processes.
+                    // Keep track of the package who's process has the highest drain.
+                    if (app.packageWithHighestDrain == null ||
+                            app.packageWithHighestDrain.startsWith("*")) {
+                        highestDrain = cpuPower;
+                        app.packageWithHighestDrain = ent.getKey();
+                    } else if (highestDrain < cpuPower && !ent.getKey().startsWith("*")) {
+                        highestDrain = cpuPower;
+                        app.packageWithHighestDrain = ent.getKey();
                     }
                 }
             }
-            if (cpuFgTime > cpuTime) {
-                if (DEBUG && cpuFgTime > cpuTime + 10000) {
+
+            // Ensure that the CPU times make sense.
+            if (app.cpuFgTime > app.cpuTime) {
+                if (DEBUG && app.cpuFgTime > app.cpuTime + 10000) {
                     Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time");
                 }
-                cpuTime = cpuFgTime; // Statistics may not have been gathered yet.
+
+                // Statistics may not have been gathered yet.
+                app.cpuTime = app.cpuFgTime;
             }
-            power /= (60*60*1000);
+
+            // Convert the CPU power to mAh
+            app.cpuPower /= (60 * 60 * 1000);
+            maxCpuPower = Math.max(maxCpuPower, app.cpuPower);
 
             // Process wake lock usage
-            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats();
+            final Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
+                    u.getWakelockStats();
+            long wakeLockTimeUs = 0;
             for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> wakelockEntry
                     : wakelockStats.entrySet()) {
-                Uid.Wakelock wakelock = wakelockEntry.getValue();
+                final Uid.Wakelock wakelock = wakelockEntry.getValue();
+
                 // Only care about partial wake locks since full wake locks
                 // are canceled when the user turns the screen off.
                 BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
                 if (timer != null) {
-                    wakelockTime += timer.getTotalTimeLocked(mRawRealtime, which);
+                    wakeLockTimeUs += timer.getTotalTimeLocked(mRawRealtime, which);
                 }
             }
-            appWakelockTimeUs += wakelockTime;
-            wakelockTime /= 1000; // convert to millis
+            app.wakeLockTime = wakeLockTimeUs / 1000; // convert to millis
+            totalAppWakelockTimeUs += wakeLockTimeUs;
 
-            // Add cost of holding a wake lock
-            p = (wakelockTime
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60*60*1000);
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wake "
-                    + wakelockTime + " power=" + makemAh(p));
-            power += p;
+            // Add cost of holding a wake lock.
+            app.wakeLockPower = (app.wakeLockTime *
+                    mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60 * 60 * 1000);
+            if (DEBUG && app.wakeLockPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wake "
+                        + app.wakeLockTime + " power=" + makemAh(app.wakeLockPower));
+            }
+            maxWakeLockPower = Math.max(maxWakeLockPower, app.wakeLockPower);
 
-            // Add cost of mobile traffic
-            final long mobileRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
-            final long mobileTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
-            final long mobileRxB = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
-            final long mobileTxB = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);
+            // Add cost of mobile traffic.
             final long mobileActive = u.getMobileRadioActiveTime(mStatsType);
+            app.mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
+            app.mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
+            app.mobileActive = mobileActive / 1000;
+            app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
+            app.mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
+            app.mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);
+
             if (mobileActive > 0) {
                 // We are tracking when the radio is up, so can use the active time to
                 // determine power use.
                 mAppMobileActive += mobileActive;
-                p = (mobilePowerPerMs * mobileActive) / 1000;
+                app.mobileRadioPower = (mobilePowerPerMs * mobileActive) / 1000;
             } else {
                 // We are not tracking when the radio is up, so must approximate power use
                 // based on the number of packets.
-                p = (mobileRx + mobileTx) * mobilePowerPerPacket;
+                app.mobileRadioPower = (app.mobileRxPackets + app.mobileTxPackets)
+                        * mobilePowerPerPacket;
             }
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
-                    + (mobileRx+mobileTx) + " active time " + mobileActive
-                    + " power=" + makemAh(p));
-            power += p;
+            if (DEBUG && app.mobileRadioPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
+                        + (app.mobileRxPackets + app.mobileTxPackets)
+                        + " active time " + mobileActive
+                        + " power=" + makemAh(app.mobileRadioPower));
+            }
+            maxMobileRadioPower = Math.max(maxMobileRadioPower, app.mobileRadioPower);
 
             // Add cost of wifi traffic
-            final long wifiRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType);
-            final long wifiTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType);
-            final long wifiRxB = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType);
-            final long wifiTxB = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType);
-            p = (wifiRx + wifiTx) * wifiPowerPerPacket;
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi packets "
-                    + (mobileRx+mobileTx) + " power=" + makemAh(p));
-            power += p;
+            app.wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType);
+            app.wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType);
+            app.wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType);
+            app.wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType);
 
-            // Add cost of keeping WIFI running.
-            long wifiRunningTimeMs = u.getWifiRunningTime(mRawRealtime, which) / 1000;
-            mAppWifiRunning += wifiRunningTimeMs;
-            p = (wifiRunningTimeMs
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi running "
-                    + wifiRunningTimeMs + " power=" + makemAh(p));
-            power += p;
-
-            // Add cost of WIFI scans
-            long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
-            p = (wifiScanTimeMs
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) / (60*60*1000);
-            if (DEBUG) Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
-                    + " power=" + makemAh(p));
-            power += p;
-            for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
-                long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
-                p = ((batchScanTimeMs
-                        * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
-                    ) / (60*60*1000);
-                if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin
-                        + " time=" + batchScanTimeMs + " power=" + makemAh(p));
-                power += p;
+            final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
+                    * wifiPowerPerPacket;
+            if (DEBUG && wifiPacketPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wifi packets "
+                        + (app.wifiRxPackets + app.wifiTxPackets)
+                        + " power=" + makemAh(wifiPacketPower));
             }
 
+            // Add cost of keeping WIFI running.
+            app.wifiRunningTime = u.getWifiRunningTime(mRawRealtime, which) / 1000;
+            mAppWifiRunning += app.wifiRunningTime;
+
+            final double wifiLockPower = (app.wifiRunningTime
+                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60 * 60 * 1000);
+            if (DEBUG && wifiLockPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wifi running "
+                        + app.wifiRunningTime + " power=" + makemAh(wifiLockPower));
+            }
+
+            // Add cost of WIFI scans
+            final long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
+            final double wifiScanPower = (wifiScanTimeMs
+                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN))
+                    /  (60 * 60 * 1000);
+            if (DEBUG && wifiScanPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
+                        + " power=" + makemAh(wifiScanPower));
+            }
+
+            // Add cost of WIFI batch scans.
+            double wifiBatchScanPower = 0;
+            for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
+                final long batchScanTimeMs =
+                        u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
+                final double batchScanPower = ((batchScanTimeMs
+                        * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
+                ) / (60 * 60 * 1000);
+                if (DEBUG && batchScanPower != 0) {
+                    Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin
+                            + " time=" + batchScanTimeMs + " power=" + makemAh(batchScanPower));
+                }
+                wifiBatchScanPower += batchScanPower;
+            }
+
+            // Add up all the WiFi costs.
+            app.wifiPower = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
+            maxWifiPower = Math.max(maxWifiPower, app.wifiPower);
+
             // Process Sensor usage
-            SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
-            int NSE = sensorStats.size();
-            for (int ise=0; ise<NSE; ise++) {
-                Uid.Sensor sensor = sensorStats.valueAt(ise);
-                int sensorHandle = sensorStats.keyAt(ise);
-                BatteryStats.Timer timer = sensor.getSensorTime();
-                long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;
-                double multiplier = 0;
+            final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
+            final int NSE = sensorStats.size();
+            for (int ise = 0; ise < NSE; ise++) {
+                final Uid.Sensor sensor = sensorStats.valueAt(ise);
+                final int sensorHandle = sensorStats.keyAt(ise);
+                final BatteryStats.Timer timer = sensor.getSensorTime();
+                final long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;
+                double sensorPower = 0;
                 switch (sensorHandle) {
                     case Uid.Sensor.GPS:
-                        multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON);
-                        gpsTime = sensorTime;
+                        app.gpsTime = sensorTime;
+                        app.gpsPower = (app.gpsTime
+                                * mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON))
+                                / (60 * 60 * 1000);
+                        sensorPower = app.gpsPower;
+                        maxGpsPower = Math.max(maxGpsPower, app.gpsPower);
                         break;
                     default:
                         List<Sensor> sensorList = sensorManager.getSensorList(
                                 android.hardware.Sensor.TYPE_ALL);
                         for (android.hardware.Sensor s : sensorList) {
                             if (s.getHandle() == sensorHandle) {
-                                multiplier = s.getPower();
+                                sensorPower = (sensorTime * s.getPower()) / (60 * 60 * 1000);
+                                app.sensorPower += sensorPower;
                                 break;
                             }
                         }
                 }
-                p = (multiplier * sensorTime) / (60*60*1000);
-                if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle
-                        + " time=" + sensorTime + " power=" + makemAh(p));
-                power += p;
+                if (DEBUG && sensorPower != 0) {
+                    Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle
+                            + " time=" + sensorTime + " power=" + makemAh(sensorPower));
+                }
+            }
+            maxSensorPower = Math.max(maxSensorPower, app.sensorPower);
+
+            final double totalUnnormalizedPower = app.cpuPower + app.wifiPower + app.wakeLockPower
+                    + app.mobileRadioPower + app.gpsPower + app.sensorPower;
+            if (DEBUG && totalUnnormalizedPower != 0) {
+                Log.d(TAG, String.format("UID %d: total power=%s",
+                        u.getUid(), makemAh(totalUnnormalizedPower)));
             }
 
-            if (DEBUG && power != 0) Log.d(TAG, String.format("UID %d: total power=%s",
-                    u.getUid(), makemAh(power)));
+            // Add the app to the list if it is consuming power.
+            if (totalUnnormalizedPower != 0 || u.getUid() == 0) {
+                appList.add(app);
+            }
+        }
 
-            // Add the app to the list if it is consuming power
-            final int userId = UserHandle.getUserId(u.getUid());
-            if (power != 0 || u.getUid() == 0) {
-                BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u,
-                        new double[] {power});
-                app.cpuTime = cpuTime;
-                app.gpsTime = gpsTime;
-                app.wifiRunningTime = wifiRunningTimeMs;
-                app.cpuFgTime = cpuFgTime;
-                app.wakeLockTime = wakelockTime;
-                app.mobileRxPackets = mobileRx;
-                app.mobileTxPackets = mobileTx;
-                app.mobileActive = mobileActive / 1000;
-                app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
-                app.wifiRxPackets = wifiRx;
-                app.wifiTxPackets = wifiTx;
-                app.mobileRxBytes = mobileRxB;
-                app.mobileTxBytes = mobileTxB;
-                app.wifiRxBytes = wifiRxB;
-                app.wifiTxBytes = wifiTxB;
-                app.packageWithHighestDrain = packageWithHighestDrain;
-                if (u.getUid() == Process.WIFI_UID) {
-                    mWifiSippers.add(app);
-                    mWifiPower += power;
-                } else if (u.getUid() == Process.BLUETOOTH_UID) {
-                    mBluetoothSippers.add(app);
-                    mBluetoothPower += power;
-                } else if (!forAllUsers && asUsers.get(userId) == null
-                        && UserHandle.getAppId(u.getUid()) >= Process.FIRST_APPLICATION_UID) {
-                    List<BatterySipper> list = mUserSippers.get(userId);
-                    if (list == null) {
-                        list = new ArrayList<BatterySipper>();
-                        mUserSippers.put(userId, list);
-                    }
-                    list.add(app);
-                    if (power != 0) {
-                        Double userPower = mUserPower.get(userId);
-                        if (userPower == null) {
-                            userPower = power;
-                        } else {
-                            userPower += power;
-                        }
-                        mUserPower.put(userId, userPower);
-                    }
+        // Fetch real power consumption from hardware.
+        double actualTotalWifiPower = 0.0;
+        if (mStats.getWifiControllerActivity(BatteryStats.CONTROLLER_ENERGY, mStatsType) != 0) {
+            final double kDefaultVoltage = 3.36;
+            final long energy = mStats.getWifiControllerActivity(
+                    BatteryStats.CONTROLLER_ENERGY, mStatsType);
+            final double voltage = mPowerProfile.getAveragePowerOrDefault(
+                    PowerProfile.OPERATING_VOLTAGE_WIFI, kDefaultVoltage);
+            actualTotalWifiPower = energy / (voltage * 1000*60*60);
+        }
+
+        final int appCount = appList.size();
+        for (int i = 0; i < appCount; i++) {
+            // Normalize power where possible.
+            final BatterySipper app = appList.get(i);
+            if (actualTotalWifiPower != 0) {
+                app.wifiPower = (app.wifiPower / maxWifiPower) * actualTotalWifiPower;
+            }
+
+            // Assign the final power consumption here.
+            final double power = app.wifiPower + app.cpuPower + app.wakeLockPower
+                    + app.mobileRadioPower + app.gpsPower + app.sensorPower;
+            app.values[0] = app.value = power;
+
+            //
+            // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list.
+            //
+
+            final int uid = app.getUid();
+            final int userId = UserHandle.getUserId(uid);
+            if (uid == Process.WIFI_UID) {
+                mWifiSippers.add(app);
+                mWifiPower += power;
+            } else if (uid == Process.BLUETOOTH_UID) {
+                mBluetoothSippers.add(app);
+                mBluetoothPower += power;
+            } else if (!forAllUsers && asUsers.get(userId) == null
+                    && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
+                // We are told to just report this user's apps as one large entry.
+                List<BatterySipper> list = mUserSippers.get(userId);
+                if (list == null) {
+                    list = new ArrayList<>();
+                    mUserSippers.put(userId, list);
+                }
+                list.add(app);
+
+                Double userPower = mUserPower.get(userId);
+                if (userPower == null) {
+                    userPower = power;
                 } else {
-                    mUsageList.add(app);
-                    if (power > mMaxPower) mMaxPower = power;
-                    if (power > mMaxRealPower) mMaxRealPower = power;
-                    mComputedPower += power;
+                    userPower += power;
                 }
-                if (u.getUid() == 0) {
-                    osApp = app;
-                }
+                mUserPower.put(userId, userPower);
+            } else {
+                mUsageList.add(app);
+                if (power > mMaxPower) mMaxPower = power;
+                if (power > mMaxRealPower) mMaxRealPower = power;
+                mComputedPower += power;
+            }
+
+            if (uid == 0) {
+                osApp = app;
             }
         }
 
@@ -641,7 +721,7 @@
         // this remainder to the OS, if possible.
         if (osApp != null) {
             long wakeTimeMillis = mBatteryUptime / 1000;
-            wakeTimeMillis -= (appWakelockTimeUs / 1000)
+            wakeTimeMillis -= (totalAppWakelockTimeUs / 1000)
                     + (mStats.getScreenOnTime(mRawRealtime, which) / 1000);
             if (wakeTimeMillis > 0) {
                 double power = (wakeTimeMillis
@@ -741,46 +821,11 @@
         for (int i=0; i<from.size(); i++) {
             BatterySipper wbs = from.get(i);
             if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTime);
-            bs.cpuTime += wbs.cpuTime;
-            bs.gpsTime += wbs.gpsTime;
-            bs.wifiRunningTime += wbs.wifiRunningTime;
-            bs.cpuFgTime += wbs.cpuFgTime;
-            bs.wakeLockTime += wbs.wakeLockTime;
-            bs.mobileRxPackets += wbs.mobileRxPackets;
-            bs.mobileTxPackets += wbs.mobileTxPackets;
-            bs.mobileActive += wbs.mobileActive;
-            bs.mobileActiveCount += wbs.mobileActiveCount;
-            bs.wifiRxPackets += wbs.wifiRxPackets;
-            bs.wifiTxPackets += wbs.wifiTxPackets;
-            bs.mobileRxBytes += wbs.mobileRxBytes;
-            bs.mobileTxBytes += wbs.mobileTxBytes;
-            bs.wifiRxBytes += wbs.wifiRxBytes;
-            bs.wifiTxBytes += wbs.wifiTxBytes;
+            bs.add(wbs);
         }
         bs.computeMobilemspp();
     }
 
-    private void addWiFiUsage() {
-        long onTimeMs = mStats.getWifiOnTime(mRawRealtime, mStatsType) / 1000;
-        long runningTimeMs = mStats.getGlobalWifiRunningTime(mRawRealtime, mStatsType) / 1000;
-        if (DEBUG) Log.d(TAG, "WIFI runningTime=" + runningTimeMs
-                + " app runningTime=" + mAppWifiRunning);
-        runningTimeMs -= mAppWifiRunning;
-        if (runningTimeMs < 0) runningTimeMs = 0;
-        double wifiPower = (onTimeMs * 0 /* TODO */
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)
-                + runningTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON))
-                / (60*60*1000);
-        if (DEBUG && wifiPower != 0) {
-            Log.d(TAG, "Wifi: time=" + runningTimeMs + " power=" + makemAh(wifiPower));
-        }
-        if ((wifiPower+mWifiPower) != 0) {
-            BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, runningTimeMs,
-                    wifiPower + mWifiPower);
-            aggregateSippers(bs, mWifiSippers, "WIFI");
-        }
-    }
-
     private void addIdleUsage() {
         long idleTimeMs = (mTypeBatteryRealtime
                 - mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000;
@@ -794,24 +839,81 @@
         }
     }
 
+    /**
+     * We do per-app blaming of WiFi activity. If energy info is reported from the controller,
+     * then only the WiFi process gets blamed here since we normalize power calculations and
+     * assign all the power drain to apps. If energy info is not reported, we attribute the
+     * difference between total running time of WiFi for all apps and the actual running time
+     * of WiFi to the WiFi subsystem.
+     */
+    private void addWiFiUsage() {
+        final long idleTimeMs = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_IDLE_TIME, mStatsType);
+        final long txTimeMs = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_TX_TIME, mStatsType);
+        final long rxTimeMs = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_RX_TIME, mStatsType);
+        final long energy = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_ENERGY, mStatsType);
+        final long totalTimeRunning = idleTimeMs + txTimeMs + rxTimeMs;
+
+        double powerDrain = 0;
+        if (energy == 0 && totalTimeRunning > 0) {
+            // Energy is not reported, which means we may have left over power drain not attributed
+            // to any app. Assign this power to the WiFi app.
+            // TODO(adamlesinski): This mimics the old behavior. However, mAppWifiRunningTime
+            // is the accumulation of the time each app kept the WiFi chip on. Multiple apps
+            // can do this at the same time, so these times do not add up to the total time
+            // the WiFi chip was on. Consider normalizing the time spent running and calculating
+            // power from that? Normalizing the times will assign a weight to each app which
+            // should better represent power usage.
+            powerDrain = ((totalTimeRunning - mAppWifiRunning)
+                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
+        }
+
+        if (DEBUG && powerDrain != 0) {
+            Log.d(TAG, "Wifi active: time=" + (txTimeMs + rxTimeMs)
+                    + " power=" + makemAh(powerDrain));
+        }
+
+        // TODO(adamlesinski): mWifiPower is already added as a BatterySipper...
+        // Are we double counting here?
+        final double power = mWifiPower + powerDrain;
+        if (power > 0) {
+            BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, totalTimeRunning, power);
+            aggregateSippers(bs, mWifiSippers, "WIFI");
+        }
+    }
+
+    /**
+     * Bluetooth usage is not attributed to any apps yet, so the entire blame goes to the
+     * Bluetooth Category.
+     */
     private void addBluetoothUsage() {
-        long btOnTimeMs = mStats.getBluetoothOnTime(mRawRealtime, mStatsType) / 1000;
-        double btPower = btOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_ON)
-                / (60*60*1000);
-        if (DEBUG && btPower != 0) {
-            Log.d(TAG, "Bluetooth: time=" + btOnTimeMs + " power=" + makemAh(btPower));
+        final double kDefaultVoltage = 3.36;
+        final long idleTimeMs = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_IDLE_TIME, mStatsType);
+        final long txTimeMs = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_TX_TIME, mStatsType);
+        final long rxTimeMs = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_RX_TIME, mStatsType);
+        final long energy = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_ENERGY, mStatsType);
+        final double voltage = mPowerProfile.getAveragePowerOrDefault(
+                PowerProfile.OPERATING_VOLTAGE_BLUETOOTH, kDefaultVoltage);
+
+        // energy is measured in mA * V * ms, and we are interested in mAh
+        final double powerDrain = energy / (voltage * 60*60*1000);
+
+        if (DEBUG && powerDrain != 0) {
+            Log.d(TAG, "Bluetooth active: time=" + (txTimeMs + rxTimeMs)
+                    + " power=" + makemAh(powerDrain));
         }
-        int btPingCount = mStats.getBluetoothPingCount();
-        double pingPower = (btPingCount
-                * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_AT_CMD))
-                / (60*60*1000);
-        if (DEBUG && pingPower != 0) {
-            Log.d(TAG, "Bluetooth ping: count=" + btPingCount + " power=" + makemAh(pingPower));
-        }
-        btPower += pingPower;
-        if ((btPower+mBluetoothPower) != 0) {
-            BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, btOnTimeMs,
-                    btPower + mBluetoothPower);
+
+        final long totalTime = idleTimeMs + txTimeMs + rxTimeMs;
+        final double power = mBluetoothPower + powerDrain;
+        if (power > 0) {
+            BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, totalTime, power);
             aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
         }
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f6c5dc7..f9b1ca1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -20,11 +20,15 @@
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
 import android.app.ActivityManager;
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiManager;
 import android.os.BadParcelableException;
 import android.os.BatteryManager;
@@ -38,6 +42,8 @@
 import android.os.ParcelFormatException;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.WorkSource;
@@ -332,6 +338,12 @@
     final LongSamplingCounter[] mNetworkPacketActivityCounters =
             new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
 
+    final LongSamplingCounter[] mBluetoothActivityCounters =
+            new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+
+    final LongSamplingCounter[] mWifiActivityCounters =
+            new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+
     boolean mWifiOn;
     StopwatchTimer mWifiOnTimer;
 
@@ -4307,6 +4319,20 @@
         return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
     }
 
+    @Override public long getBluetoothControllerActivity(int type, int which) {
+        if (type >= 0 && type < mBluetoothActivityCounters.length) {
+            return mBluetoothActivityCounters[type].getCountLocked(which);
+        }
+        return 0;
+    }
+
+    @Override public long getWifiControllerActivity(int type, int which) {
+        if (type >= 0 && type < mWifiActivityCounters.length) {
+            return mWifiActivityCounters[type].getCountLocked(which);
+        }
+        return 0;
+    }
+
     @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
         return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
@@ -4749,6 +4775,14 @@
         }
 
         @Override
+        public int getWifiScanCount(int which) {
+            if (mWifiScanTimer == null) {
+                return 0;
+            }
+            return mWifiScanTimer.getCountLocked(which);
+        }
+
+        @Override
         public long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which) {
             if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
             if (mWifiBatchedScanTimer[csphBin] == null) {
@@ -4758,6 +4792,15 @@
         }
 
         @Override
+        public int getWifiBatchedScanCount(int csphBin, int which) {
+            if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
+            if (mWifiBatchedScanTimer[csphBin] == null) {
+                return 0;
+            }
+            return mWifiBatchedScanTimer[csphBin].getCountLocked(which);
+        }
+
+        @Override
         public long getWifiMulticastTime(long elapsedRealtimeUs, int which) {
             if (mWifiMulticastTimer == null) {
                 return 0;
@@ -5601,17 +5644,17 @@
             boolean mActive = true;
 
             /**
-             * Total time (in 1/100 sec) spent executing in user code.
+             * Total time (in ms) spent executing in user code.
              */
             long mUserTime;
 
             /**
-             * Total time (in 1/100 sec) spent executing in kernel code.
+             * Total time (in ms) spent executing in kernel code.
              */
             long mSystemTime;
 
             /**
-             * Amount of time the process was running in the foreground.
+             * Amount of time (in ms) the process was running in the foreground.
              */
             long mForegroundTime;
 
@@ -6635,6 +6678,10 @@
             mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
             mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
         }
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+            mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+        }
         mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
         mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -7222,6 +7269,10 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].reset(false);
         }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].reset(false);
+            mWifiActivityCounters[i].reset(false);
+        }
         mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
 
         for (int i=0; i<mUidStats.size(); i++) {
@@ -7308,6 +7359,9 @@
     public void pullPendingStateUpdatesLocked() {
         updateKernelWakelocksLocked();
         updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
+        // TODO(adamlesinski): enable when bluedroid stops deadlocking. b/19248786
+        // updateBluetoothControllerActivityLocked();
+        updateWifiControllerActivityLocked();
         if (mOnBatteryInternal) {
             final boolean screenOn = mScreenState == Display.STATE_ON;
             updateDischargeScreenLevelsLocked(screenOn, screenOn);
@@ -7744,6 +7798,65 @@
         }
     }
 
+    private void updateBluetoothControllerActivityLocked() {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter == null) {
+            return;
+        }
+
+        // We read the data even if we are not on battery. Each read clears
+        // the previous data, so we must always read to make sure the
+        // data is for the current interval.
+        BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
+                BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
+        if (info == null || !info.isValid() || !mOnBatteryInternal) {
+            // Bad info or we are not on battery.
+            return;
+        }
+
+        mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+                info.getControllerRxTimeMillis());
+        mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+                info.getControllerTxTimeMillis());
+        mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+                info.getControllerIdleTimeMillis());
+        mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+                info.getControllerEnergyUsed());
+    }
+
+    private void updateWifiControllerActivityLocked() {
+        IWifiManager wifiManager = IWifiManager.Stub.asInterface(
+                ServiceManager.getService(Context.WIFI_SERVICE));
+        if (wifiManager == null) {
+            return;
+        }
+
+        WifiActivityEnergyInfo info;
+        try {
+            // We read the data even if we are not on battery. Each read clears
+            // the previous data, so we must always read to make sure the
+            // data is for the current interval.
+            info = wifiManager.reportActivityInfo();
+        } catch (RemoteException e) {
+            // Nothing to report, WiFi is dead.
+            return;
+        }
+
+        if (info == null || !info.isValid() || !mOnBatteryInternal) {
+            // Bad info or we are not on battery.
+            return;
+        }
+
+        mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+                info.getControllerRxTimeMillis());
+        mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+                info.getControllerTxTimeMillis());
+        mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+                info.getControllerIdleTimeMillis());
+        mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+                info.getControllerEnergyUsed());
+    }
+
     public long getAwakeTimeBattery() {
         return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
     }
@@ -8458,6 +8571,15 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
         }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in);
+        }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i].readSummaryFromParcelLocked(in);
+        }
+
         mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
         mFlashlightOn = false;
         mFlashlightOnTimer.readSummaryFromParcelLocked(in);
@@ -8746,6 +8868,12 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out);
+        }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i].writeSummaryFromParcelLocked(out);
+        }
         out.writeInt(mNumConnectivityChange);
         mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
 
@@ -9050,6 +9178,15 @@
             mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
                     null, mOnBatteryTimeBase, in);
         }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        }
+
         mNumConnectivityChange = in.readInt();
         mLoadedNumConnectivityChange = in.readInt();
         mUnpluggedNumConnectivityChange = in.readInt();
@@ -9195,6 +9332,12 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
         }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].writeToParcel(out);
+        }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i].writeToParcel(out);
+        }
         out.writeInt(mNumConnectivityChange);
         out.writeInt(mLoadedNumConnectivityChange);
         out.writeInt(mUnpluggedNumConnectivityChange);
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index b3bafa1..944eb5a 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -76,6 +76,11 @@
     public static final String POWER_WIFI_ACTIVE = "wifi.active";
 
     /**
+     * Operating voltage of the WiFi controller.
+     */
+    public static final String OPERATING_VOLTAGE_WIFI = "wifi.voltage";
+
+    /**
      * Power consumption when GPS is on.
      */
     public static final String POWER_GPS_ON = "gps.on";
@@ -96,6 +101,11 @@
     public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
 
     /**
+     * Operating voltage of the Bluetooth controller.
+     */
+    public static final String OPERATING_VOLTAGE_BLUETOOTH = "bluetooth.voltage";
+
+    /**
      * Power consumption when screen is on, not including the backlight power.
      */
     public static final String POWER_SCREEN_ON = "screen.on";
@@ -224,11 +234,13 @@
     }
 
     /**
-     * Returns the average current in mA consumed by the subsystem 
+     * Returns the average current in mA consumed by the subsystem, or the given
+     * default value if the subsystem has no recorded value.
      * @param type the subsystem type
+     * @param defaultValue the value to return if the subsystem has no recorded value.
      * @return the average current in milliAmps.
      */
-    public double getAveragePower(String type) {
+    public double getAveragePowerOrDefault(String type, double defaultValue) {
         if (sPowerMap.containsKey(type)) {
             Object data = sPowerMap.get(type);
             if (data instanceof Double[]) {
@@ -237,9 +249,18 @@
                 return (Double) sPowerMap.get(type);
             }
         } else {
-            return 0;
+            return defaultValue;
         }
     }
+
+    /**
+     * Returns the average current in mA consumed by the subsystem
+     * @param type the subsystem type
+     * @return the average current in milliAmps.
+     */
+    public double getAveragePower(String type) {
+        return getAveragePowerOrDefault(type, 0);
+    }
     
     /**
      * Returns the average current in mA consumed by the subsystem for the given level.
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 501e0ec..2983047 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -22,11 +22,13 @@
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.system.OsConstants;
 import android.util.Slog;
 
 import com.android.internal.util.FastPrintWriter;
 
 import libcore.io.IoUtils;
+import libcore.io.Libcore;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -130,6 +132,9 @@
 
     private final boolean mIncludeThreads;
 
+    // How long a CPU jiffy is in milliseconds.
+    private final long mJiffyMillis;
+
     private float mLoad1 = 0;
     private float mLoad5 = 0;
     private float mLoad15 = 0;
@@ -269,6 +274,8 @@
 
     public ProcessCpuTracker(boolean includeThreads) {
         mIncludeThreads = includeThreads;
+        long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK);
+        mJiffyMillis = 1000/jiffyHz;
     }
 
     public void onLoadChanged(float load1, float load5, float load15) {
@@ -294,15 +301,15 @@
         if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
                 null, sysCpu, null)) {
             // Total user time is user + nice time.
-            final long usertime = sysCpu[0]+sysCpu[1];
+            final long usertime = (sysCpu[0]+sysCpu[1]) * mJiffyMillis;
             // Total system time is simply system time.
-            final long systemtime = sysCpu[2];
+            final long systemtime = sysCpu[2] * mJiffyMillis;
             // Total idle time is simply idle time.
-            final long idletime = sysCpu[3];
+            final long idletime = sysCpu[3] * mJiffyMillis;
             // Total irq time is iowait + irq + softirq time.
-            final long iowaittime = sysCpu[4];
-            final long irqtime = sysCpu[5];
-            final long softirqtime = sysCpu[6];
+            final long iowaittime = sysCpu[4] * mJiffyMillis;
+            final long irqtime = sysCpu[5] * mJiffyMillis;
+            final long softirqtime = sysCpu[6] * mJiffyMillis;
 
             // This code is trying to avoid issues with idle time going backwards,
             // but currently it gets into situations where it triggers most of the time. :(
@@ -318,10 +325,11 @@
                 mRelStatsAreGood = true;
 
                 if (DEBUG) {
-                    Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
-                          + " S:" + sysCpu[2] + " I:" + sysCpu[3]
-                          + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
-                          + " O:" + sysCpu[6]);
+                    Slog.i("Load", "Total U:" + (sysCpu[0]*mJiffyMillis)
+                          + " N:" + (sysCpu[1]*mJiffyMillis)
+                          + " S:" + (sysCpu[2]*mJiffyMillis) + " I:" + (sysCpu[3]*mJiffyMillis)
+                          + " W:" + (sysCpu[4]*mJiffyMillis) + " Q:" + (sysCpu[5]*mJiffyMillis)
+                          + " O:" + (sysCpu[6]*mJiffyMillis));
                     Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
                           + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
                 }
@@ -414,8 +422,8 @@
 
                     final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
                     final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
-                    final long utime = procStats[PROCESS_STAT_UTIME];
-                    final long stime = procStats[PROCESS_STAT_STIME];
+                    final long utime = procStats[PROCESS_STAT_UTIME] * mJiffyMillis;
+                    final long stime = procStats[PROCESS_STAT_STIME] * mJiffyMillis;
 
                     if (utime == st.base_utime && stime == st.base_stime) {
                         st.rel_utime = 0;
@@ -489,8 +497,8 @@
                         st.baseName = procStatsString[0];
                         st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
                         st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
-                        st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
-                        st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
+                        st.base_utime = procStats[PROCESS_FULL_STAT_UTIME] * mJiffyMillis;
+                        st.base_stime = procStats[PROCESS_FULL_STAT_STIME] * mJiffyMillis;
                     } else {
                         Slog.i(TAG, "Skipping kernel process pid " + pid
                                 + " name " + procStatsString[0]);
@@ -576,7 +584,7 @@
                     null, statsData, null)) {
                 long time = statsData[PROCESS_STAT_UTIME]
                         + statsData[PROCESS_STAT_STIME];
-                return time;
+                return time * mJiffyMillis;
             }
             return 0;
         }
@@ -777,7 +785,7 @@
         for (int i=0; i<N; i++) {
             Stats st = mWorkingProcs.get(i);
             printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": "  "),
-                    st.pid, st.name, (int)(st.rel_uptime+5)/10,
+                    st.pid, st.name, (int)st.rel_uptime,
                     st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
             if (!st.removed && st.workingThreads != null) {
                 int M = st.workingThreads.size();
@@ -785,7 +793,7 @@
                     Stats tst = st.workingThreads.get(j);
                     printProcessCPU(pw,
                             tst.added ? "   +" : (tst.removed ? "   -": "    "),
-                            tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
+                            tst.pid, tst.name, (int)st.rel_uptime,
                             tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
                 }
             }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 5fc5b58..7acd8f5 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -76,7 +76,6 @@
     private final DataOutputStream mSocketOutStream;
     private final BufferedReader mSocketReader;
     private final Credentials peer;
-    private final String peerSecurityContext;
     private final String abiList;
 
     /**
@@ -97,15 +96,13 @@
                 new InputStreamReader(socket.getInputStream()), 256);
 
         mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
-                
+
         try {
             peer = mSocket.getPeerCredentials();
         } catch (IOException ex) {
             Log.e(TAG, "Cannot read peer credentials", ex);
             throw ex;
         }
-
-        peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor());
     }
 
     /**
@@ -177,10 +174,8 @@
                         ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
             }
 
-            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
+            applyUidSecurityPolicy(parsedArgs, peer);
+            applyInvokeWithSecurityPolicy(parsedArgs, peer);
 
             applyDebuggerSystemProperty(parsedArgs);
             applyInvokeWithSystemProperty(parsedArgs);
@@ -581,7 +576,7 @@
         }
 
         // See bug 1092107: large argc can be used for a DOS attack
-        if (argc > MAX_ZYGOTE_ARGC) {   
+        if (argc > MAX_ZYGOTE_ARGC) {
             throw new IOException("max arg count exceeded");
         }
 
@@ -598,63 +593,30 @@
     }
 
     /**
-     * Applies zygote security policy per bugs #875058 and #1082165. 
-     * Based on the credentials of the process issuing a zygote command:
-     * <ol>
-     * <li> uid 0 (root) may specify any uid, gid, and setgroups() list
-     * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
+     * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
      * operation. It may also specify any gid and setgroups() list it chooses.
      * In factory test mode, it may specify any UID.
-     * <li> Any other uid may not specify any uid, gid, or setgroups list. The
-     * uid and gid will be inherited from the requesting process.
-     * </ul>
      *
      * @param args non-null; zygote spawner arguments
      * @param peer non-null; peer credentials
      * @throws ZygoteSecurityException
      */
-    private static void applyUidSecurityPolicy(Arguments args, Credentials peer,
-            String peerSecurityContext)
+    private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
             throws ZygoteSecurityException {
 
-        int peerUid = peer.getUid();
-
-        if (peerUid == 0) {
-            // Root can do what it wants
-        } else if (peerUid == Process.SYSTEM_UID ) {
-            // System UID is restricted, except in factory test mode
+        if (peer.getUid() == Process.SYSTEM_UID) {
             String factoryTest = SystemProperties.get("ro.factorytest");
             boolean uidRestricted;
 
             /* In normal operation, SYSTEM_UID can only specify a restricted
              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
              */
-            uidRestricted  
-                 = !(factoryTest.equals("1") || factoryTest.equals("2"));
+            uidRestricted = !(factoryTest.equals("1") || factoryTest.equals("2"));
 
-            if (uidRestricted
-                    && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
+            if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
                 throw new ZygoteSecurityException(
                         "System UID may not launch process with UID < "
-                                + Process.SYSTEM_UID);
-            }
-        } else {
-            // Everything else
-            if (args.uidSpecified || args.gidSpecified
-                || args.gids != null) {
-                throw new ZygoteSecurityException(
-                        "App UIDs may not specify uid's or gid's");
-            }
-        }
-
-        if (args.uidSpecified || args.gidSpecified || args.gids != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyids");
-            if (!allowed) {
-                throw new ZygoteSecurityException(
-                        "Peer may not specify uid's or gid's");
+                        + Process.SYSTEM_UID);
             }
         }
 
@@ -669,7 +631,6 @@
         }
     }
 
-
     /**
      * Applies debugger system properties to the zygote arguments.
      *
@@ -686,44 +647,6 @@
     }
 
     /**
-     * Applies zygote security policy per bug #1042973. Based on the credentials
-     * of the process issuing a zygote command:
-     * <ol>
-     * <li> peers of  uid 0 (root) and uid 1000 (Process.SYSTEM_UID)
-     * may specify any rlimits.
-     * <li> All other uids may not specify rlimits.
-     * </ul>
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyRlimitSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-
-        int peerUid = peer.getUid();
-
-        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
-            // All peers with UID other than root or SYSTEM_UID
-            if (args.rlimits != null) {
-                throw new ZygoteSecurityException(
-                        "This UID may not specify rlimits.");
-            }
-        }
-
-        if (args.rlimits != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyrlimits");
-            if (!allowed) {
-                throw new ZygoteSecurityException(
-                        "Peer may not specify rlimits");
-            }
-         }
-    }
-
-    /**
      * Applies zygote security policy.
      * Based on the credentials of the process issuing a zygote command:
      * <ol>
@@ -736,8 +659,7 @@
      * @param peer non-null; peer credentials
      * @throws ZygoteSecurityException
      */
-    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,
-            String peerSecurityContext)
+    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
             throws ZygoteSecurityException {
         int peerUid = peer.getUid();
 
@@ -745,52 +667,6 @@
             throw new ZygoteSecurityException("Peer is not permitted to specify "
                     + "an explicit invoke-with wrapper command");
         }
-
-        if (args.invokeWith != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyinvokewith");
-            if (!allowed) {
-                throw new ZygoteSecurityException("Peer is not permitted to specify "
-                    + "an explicit invoke-with wrapper command");
-            }
-        }
-    }
-
-    /**
-     * Applies zygote security policy for SELinux information.
-     *
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyseInfoSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-        int peerUid = peer.getUid();
-
-        if (args.seInfo == null) {
-            // nothing to check
-            return;
-        }
-
-        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
-            // All peers with UID other than root or SYSTEM_UID
-            throw new ZygoteSecurityException(
-                    "This UID may not specify SELinux info.");
-        }
-
-        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                     peerSecurityContext,
-                                                     "zygote",
-                                                     "specifyseinfo");
-        if (!allowed) {
-            throw new ZygoteSecurityException(
-                    "Peer may not specify SELinux info");
-        }
-
-        return;
     }
 
     /**
@@ -800,20 +676,18 @@
      */
     public static void applyInvokeWithSystemProperty(Arguments args) {
         if (args.invokeWith == null && args.niceName != null) {
-            if (args.niceName != null) {
-                String property = "wrap." + args.niceName;
-                if (property.length() > 31) {
-                    // Properties with a trailing "." are illegal.
-                    if (property.charAt(30) != '.') {
-                        property = property.substring(0, 31);
-                    } else {
-                        property = property.substring(0, 30);
-                    }
+            String property = "wrap." + args.niceName;
+            if (property.length() > 31) {
+                // Properties with a trailing "." are illegal.
+                if (property.charAt(30) != '.') {
+                    property = property.substring(0, 31);
+                } else {
+                    property = property.substring(0, 30);
                 }
-                args.invokeWith = SystemProperties.get(property);
-                if (args.invokeWith != null && args.invokeWith.length() == 0) {
-                    args.invokeWith = null;
-                }
+            }
+            args.invokeWith = SystemProperties.get(property);
+            if (args.invokeWith != null && args.invokeWith.length() == 0) {
+                args.invokeWith = null;
             }
         }
     }
diff --git a/core/java/com/android/internal/transition/EpicenterClipReveal.java b/core/java/com/android/internal/transition/EpicenterClipReveal.java
index d8a7f16..abb50c1 100644
--- a/core/java/com/android/internal/transition/EpicenterClipReveal.java
+++ b/core/java/com/android/internal/transition/EpicenterClipReveal.java
@@ -16,6 +16,7 @@
 package com.android.internal.transition;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.RectEvaluator;
 import android.content.Context;
@@ -75,13 +76,13 @@
             return null;
         }
 
-        final Rect start = getEpicenter();
         final Rect end = getBestRect(endValues);
+        final Rect start = getEpicenterOrCenter(end);
 
         // Prepare the view.
         view.setClipBounds(start);
 
-        return createRectAnimator(view, start, end);
+        return createRectAnimator(view, start, end, endValues);
     }
 
     @Override
@@ -92,12 +93,23 @@
         }
 
         final Rect start = getBestRect(startValues);
-        final Rect end = getEpicenter();
+        final Rect end = getEpicenterOrCenter(start);
 
         // Prepare the view.
         view.setClipBounds(start);
 
-        return createRectAnimator(view, start, end);
+        return createRectAnimator(view, start, end, endValues);
+    }
+
+    private Rect getEpicenterOrCenter(Rect bestRect) {
+        final Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            return epicenter;
+        }
+
+        int centerX = bestRect.centerX();
+        int centerY = bestRect.centerY();
+        return new Rect(centerX, centerY, centerX, centerY);
     }
 
     private Rect getBestRect(TransitionValues values) {
@@ -108,8 +120,17 @@
         return clipRect;
     }
 
-    private Animator createRectAnimator(View view, Rect start, Rect end) {
+    private Animator createRectAnimator(final View view, Rect start, Rect end,
+            TransitionValues endValues) {
+        final Rect terminalClip = (Rect) endValues.values.get(PROPNAME_CLIP);
         final RectEvaluator evaluator = new RectEvaluator(new Rect());
-        return ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end);
+        ObjectAnimator anim = ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                view.setClipBounds(terminalClip);
+            }
+        });
+        return anim;
     }
 }
diff --git a/core/java/com/android/internal/widget/PagerAdapter.java b/core/java/com/android/internal/widget/PagerAdapter.java
new file mode 100644
index 0000000..910a720
--- /dev/null
+++ b/core/java/com/android/internal/widget/PagerAdapter.java
@@ -0,0 +1,320 @@
+/*
+ * 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.database.DataSetObservable;
+import android.database.DataSetObserver;
+import android.os.Parcelable;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Base class providing the adapter to populate pages inside of
+ * a {@link android.support.v4.view.ViewPager}.  You will most likely want to use a more
+ * specific implementation of this, such as
+ * {@link android.support.v4.app.FragmentPagerAdapter} or
+ * {@link android.support.v4.app.FragmentStatePagerAdapter}.
+ *
+ * <p>When you implement a PagerAdapter, you must override the following methods
+ * at minimum:</p>
+ * <ul>
+ * <li>{@link #instantiateItem(android.view.ViewGroup, int)}</li>
+ * <li>{@link #destroyItem(android.view.ViewGroup, int, Object)}</li>
+ * <li>{@link #getCount()}</li>
+ * <li>{@link #isViewFromObject(android.view.View, Object)}</li>
+ * </ul>
+ *
+ * <p>PagerAdapter is more general than the adapters used for
+ * {@link android.widget.AdapterView AdapterViews}. Instead of providing a
+ * View recycling mechanism directly ViewPager uses callbacks to indicate the
+ * steps taken during an update. A PagerAdapter may implement a form of View
+ * recycling if desired or use a more sophisticated method of managing page
+ * Views such as Fragment transactions where each page is represented by its
+ * own Fragment.</p>
+ *
+ * <p>ViewPager associates each page with a key Object instead of working with
+ * Views directly. This key is used to track and uniquely identify a given page
+ * independent of its position in the adapter. A call to the PagerAdapter method
+ * {@link #startUpdate(android.view.ViewGroup)} indicates that the contents of the ViewPager
+ * are about to change. One or more calls to {@link #instantiateItem(android.view.ViewGroup, int)}
+ * and/or {@link #destroyItem(android.view.ViewGroup, int, Object)} will follow, and the end
+ * of an update will be signaled by a call to {@link #finishUpdate(android.view.ViewGroup)}.
+ * By the time {@link #finishUpdate(android.view.ViewGroup) finishUpdate} returns the views
+ * associated with the key objects returned by
+ * {@link #instantiateItem(android.view.ViewGroup, int) instantiateItem} should be added to
+ * the parent ViewGroup passed to these methods and the views associated with
+ * the keys passed to {@link #destroyItem(android.view.ViewGroup, int, Object) destroyItem}
+ * should be removed. The method {@link #isViewFromObject(android.view.View, Object)} identifies
+ * whether a page View is associated with a given key object.</p>
+ *
+ * <p>A very simple PagerAdapter may choose to use the page Views themselves
+ * as key objects, returning them from {@link #instantiateItem(android.view.ViewGroup, int)}
+ * after creation and adding them to the parent ViewGroup. A matching
+ * {@link #destroyItem(android.view.ViewGroup, int, Object)} implementation would remove the
+ * View from the parent ViewGroup and {@link #isViewFromObject(android.view.View, Object)}
+ * could be implemented as <code>return view == object;</code>.</p>
+ *
+ * <p>PagerAdapter supports data set changes. Data set changes must occur on the
+ * main thread and must end with a call to {@link #notifyDataSetChanged()} similar
+ * to AdapterView adapters derived from {@link android.widget.BaseAdapter}. A data
+ * set change may involve pages being added, removed, or changing position. The
+ * ViewPager will keep the current page active provided the adapter implements
+ * the method {@link #getItemPosition(Object)}.</p>
+ */
+public abstract class PagerAdapter {
+    private DataSetObservable mObservable = new DataSetObservable();
+
+    public static final int POSITION_UNCHANGED = -1;
+    public static final int POSITION_NONE = -2;
+
+    /**
+     * Return the number of views available.
+     */
+    public abstract int getCount();
+
+    /**
+     * Called when a change in the shown pages is going to start being made.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     */
+    public void startUpdate(ViewGroup container) {
+        startUpdate((View) container);
+    }
+
+    /**
+     * Create the page for the given position.  The adapter is responsible
+     * for adding the view to the container given here, although it only
+     * must ensure this is done by the time it returns from
+     * {@link #finishUpdate(android.view.ViewGroup)}.
+     *
+     * @param container The containing View in which the page will be shown.
+     * @param position The page position to be instantiated.
+     * @return Returns an Object representing the new page.  This does not
+     * need to be a View, but can be some other container of the page.
+     */
+    public Object instantiateItem(ViewGroup container, int position) {
+        return instantiateItem((View) container, position);
+    }
+
+    /**
+     * Remove a page for the given position.  The adapter is responsible
+     * for removing the view from its container, although it only must ensure
+     * this is done by the time it returns from {@link #finishUpdate(android.view.ViewGroup)}.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position to be removed.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     */
+    public void destroyItem(ViewGroup container, int position, Object object) {
+        destroyItem((View) container, position, object);
+    }
+
+    /**
+     * Called to inform the adapter of which item is currently considered to
+     * be the "primary", that is the one show to the user as the current page.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position that is now the primary.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     */
+    public void setPrimaryItem(ViewGroup container, int position, Object object) {
+        setPrimaryItem((View) container, position, object);
+    }
+
+    /**
+     * Called when the a change in the shown pages has been completed.  At this
+     * point you must ensure that all of the pages have actually been added or
+     * removed from the container as appropriate.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     */
+    public void finishUpdate(ViewGroup container) {
+        finishUpdate((View) container);
+    }
+
+    /**
+     * Called when a change in the shown pages is going to start being made.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     *
+     * @deprecated Use {@link #startUpdate(android.view.ViewGroup)}
+     */
+    public void startUpdate(View container) {
+    }
+
+    /**
+     * Create the page for the given position.  The adapter is responsible
+     * for adding the view to the container given here, although it only
+     * must ensure this is done by the time it returns from
+     * {@link #finishUpdate(android.view.ViewGroup)}.
+     *
+     * @param container The containing View in which the page will be shown.
+     * @param position The page position to be instantiated.
+     * @return Returns an Object representing the new page.  This does not
+     * need to be a View, but can be some other container of the page.
+     *
+     * @deprecated Use {@link #instantiateItem(android.view.ViewGroup, int)}
+     */
+    public Object instantiateItem(View container, int position) {
+        throw new UnsupportedOperationException(
+                "Required method instantiateItem was not overridden");
+    }
+
+    /**
+     * Remove a page for the given position.  The adapter is responsible
+     * for removing the view from its container, although it only must ensure
+     * this is done by the time it returns from {@link #finishUpdate(android.view.View)}.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position to be removed.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     *
+     * @deprecated Use {@link #destroyItem(android.view.ViewGroup, int, Object)}
+     */
+    public void destroyItem(View container, int position, Object object) {
+        throw new UnsupportedOperationException("Required method destroyItem was not overridden");
+    }
+
+    /**
+     * Called to inform the adapter of which item is currently considered to
+     * be the "primary", that is the one show to the user as the current page.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position that is now the primary.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     *
+     * @deprecated Use {@link #setPrimaryItem(android.view.ViewGroup, int, Object)}
+     */
+    public void setPrimaryItem(View container, int position, Object object) {
+    }
+
+    /**
+     * Called when the a change in the shown pages has been completed.  At this
+     * point you must ensure that all of the pages have actually been added or
+     * removed from the container as appropriate.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     *
+     * @deprecated Use {@link #finishUpdate(android.view.ViewGroup)}
+     */
+    public void finishUpdate(View container) {
+    }
+
+    /**
+     * Determines whether a page View is associated with a specific key object
+     * as returned by {@link #instantiateItem(android.view.ViewGroup, int)}. This method is
+     * required for a PagerAdapter to function properly.
+     *
+     * @param view Page View to check for association with <code>object</code>
+     * @param object Object to check for association with <code>view</code>
+     * @return true if <code>view</code> is associated with the key object <code>object</code>
+     */
+    public abstract boolean isViewFromObject(View view, Object object);
+
+    /**
+     * Save any instance state associated with this adapter and its pages that should be
+     * restored if the current UI state needs to be reconstructed.
+     *
+     * @return Saved state for this adapter
+     */
+    public Parcelable saveState() {
+        return null;
+    }
+
+    /**
+     * Restore any instance state associated with this adapter and its pages
+     * that was previously saved by {@link #saveState()}.
+     *
+     * @param state State previously saved by a call to {@link #saveState()}
+     * @param loader A ClassLoader that should be used to instantiate any restored objects
+     */
+    public void restoreState(Parcelable state, ClassLoader loader) {
+    }
+
+    /**
+     * Called when the host view is attempting to determine if an item's position
+     * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given
+     * item has not changed or {@link #POSITION_NONE} if the item is no longer present
+     * in the adapter.
+     *
+     * <p>The default implementation assumes that items will never
+     * change position and always returns {@link #POSITION_UNCHANGED}.
+     *
+     * @param object Object representing an item, previously returned by a call to
+     *               {@link #instantiateItem(android.view.View, int)}.
+     * @return object's new position index from [0, {@link #getCount()}),
+     *         {@link #POSITION_UNCHANGED} if the object's position has not changed,
+     *         or {@link #POSITION_NONE} if the item is no longer present.
+     */
+    public int getItemPosition(Object object) {
+        return POSITION_UNCHANGED;
+    }
+
+    /**
+     * This method should be called by the application if the data backing this adapter has changed
+     * and associated views should update.
+     */
+    public void notifyDataSetChanged() {
+        mObservable.notifyChanged();
+    }
+
+    /**
+     * Register an observer to receive callbacks related to the adapter's data changing.
+     *
+     * @param observer The {@link android.database.DataSetObserver} which will receive callbacks.
+     */
+    public void registerDataSetObserver(DataSetObserver observer) {
+        mObservable.registerObserver(observer);
+    }
+
+    /**
+     * Unregister an observer from callbacks related to the adapter's data changing.
+     *
+     * @param observer The {@link android.database.DataSetObserver} which will be unregistered.
+     */
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        mObservable.unregisterObserver(observer);
+    }
+
+    /**
+     * This method may be called by the ViewPager to obtain a title string
+     * to describe the specified page. This method may return null
+     * indicating no title for this page. The default implementation returns
+     * null.
+     *
+     * @param position The position of the title requested
+     * @return A title for the requested page
+     */
+    public CharSequence getPageTitle(int position) {
+        return null;
+    }
+
+    /**
+     * Returns the proportional width of a given page as a percentage of the
+     * ViewPager's measured width from (0.f-1.f]
+     *
+     * @param position The position of the page requested
+     * @return Proportional width for the given page position
+     */
+    public float getPageWidth(int position) {
+        return 1.f;
+    }
+}
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
new file mode 100644
index 0000000..f916e6f
--- /dev/null
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -0,0 +1,2866 @@
+/*
+ * 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.annotation.DrawableRes;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.FocusFinder;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityRecord;
+import android.view.animation.Interpolator;
+import android.widget.EdgeEffect;
+import android.widget.Scroller;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Layout manager that allows the user to flip left and right
+ * through pages of data.  You supply an implementation of a
+ * {@link android.support.v4.view.PagerAdapter} to generate the pages that the view shows.
+ *
+ * <p>Note this class is currently under early design and
+ * development.  The API will likely change in later updates of
+ * the compatibility library, requiring changes to the source code
+ * of apps when they are compiled against the newer version.</p>
+ *
+ * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment},
+ * which is a convenient way to supply and manage the lifecycle of each page.
+ * There are standard adapters implemented for using fragments with the ViewPager,
+ * which cover the most common use cases.  These are
+ * {@link android.support.v4.app.FragmentPagerAdapter} and
+ * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these
+ * classes have simple code showing how to build a full user interface
+ * with them.
+ *
+ * <p>For more information about how to use ViewPager, read <a
+ * href="{@docRoot}training/implementing-navigation/lateral.html">Creating Swipe Views with
+ * Tabs</a>.</p>
+ *
+ * <p>Below is a more complicated example of ViewPager, using it in conjunction
+ * with {@link android.app.ActionBar} tabs.  You can find other examples of using
+ * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code.
+ *
+ * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
+ *      complete}
+ */
+public class ViewPager extends ViewGroup {
+    private static final String TAG = "ViewPager";
+    private static final boolean DEBUG = false;
+
+    private static final boolean USE_CACHE = false;
+
+    private static final int DEFAULT_OFFSCREEN_PAGES = 1;
+    private static final int MAX_SETTLE_DURATION = 600; // ms
+    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
+
+    private static final int DEFAULT_GUTTER_SIZE = 16; // dips
+
+    private static final int MIN_FLING_VELOCITY = 400; // dips
+
+    private static final int[] LAYOUT_ATTRS = new int[] {
+        com.android.internal.R.attr.layout_gravity
+    };
+
+    /**
+     * Used to track what the expected number of items in the adapter should be.
+     * If the app changes this when we don't expect it, we'll throw a big obnoxious exception.
+     */
+    private int mExpectedAdapterCount;
+
+    static class ItemInfo {
+        Object object;
+        int position;
+        boolean scrolling;
+        float widthFactor;
+        float offset;
+    }
+
+    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){
+        @Override
+        public int compare(ItemInfo lhs, ItemInfo rhs) {
+            return lhs.position - rhs.position;
+        }
+    };
+
+    private static final Interpolator sInterpolator = new Interpolator() {
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t * t * t * t * t + 1.0f;
+        }
+    };
+
+    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
+    private final ItemInfo mTempItem = new ItemInfo();
+
+    private final Rect mTempRect = new Rect();
+
+    private PagerAdapter mAdapter;
+    private int mCurItem;   // Index of currently displayed page.
+    private int mRestoredCurItem = -1;
+    private Parcelable mRestoredAdapterState = null;
+    private ClassLoader mRestoredClassLoader = null;
+    private Scroller mScroller;
+    private PagerObserver mObserver;
+
+    private int mPageMargin;
+    private Drawable mMarginDrawable;
+    private int mTopPageBounds;
+    private int mBottomPageBounds;
+
+    // Offsets of the first and last items, if known.
+    // Set during population, used to determine if we are at the beginning
+    // or end of the pager data set during touch scrolling.
+    private float mFirstOffset = -Float.MAX_VALUE;
+    private float mLastOffset = Float.MAX_VALUE;
+
+    private int mChildWidthMeasureSpec;
+    private int mChildHeightMeasureSpec;
+    private boolean mInLayout;
+
+    private boolean mScrollingCacheEnabled;
+
+    private boolean mPopulatePending;
+    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
+
+    private boolean mIsBeingDragged;
+    private boolean mIsUnableToDrag;
+    private int mDefaultGutterSize;
+    private int mGutterSize;
+    private int mTouchSlop;
+    /**
+     * Position of the last motion event.
+     */
+    private float mLastMotionX;
+    private float mLastMotionY;
+    private float mInitialMotionX;
+    private float mInitialMotionY;
+    /**
+     * ID of the active pointer. This is used to retain consistency during
+     * drags/flings if multiple pointers are used.
+     */
+    private int mActivePointerId = INVALID_POINTER;
+    /**
+     * Sentinel value for no current active pointer.
+     * Used by {@link #mActivePointerId}.
+     */
+    private static final int INVALID_POINTER = -1;
+
+    /**
+     * Determines speed during touch scrolling
+     */
+    private VelocityTracker mVelocityTracker;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
+    private int mFlingDistance;
+    private int mCloseEnough;
+
+    // If the pager is at least this close to its final position, complete the scroll
+    // on touch down and let the user interact with the content inside instead of
+    // "catching" the flinging pager.
+    private static final int CLOSE_ENOUGH = 2; // dp
+
+    private boolean mFakeDragging;
+    private long mFakeDragBeginTime;
+
+    private EdgeEffect mLeftEdge;
+    private EdgeEffect mRightEdge;
+
+    private boolean mFirstLayout = true;
+    private boolean mNeedCalculatePageOffsets = false;
+    private boolean mCalledSuper;
+    private int mDecorChildCount;
+
+    private OnPageChangeListener mOnPageChangeListener;
+    private OnPageChangeListener mInternalPageChangeListener;
+    private OnAdapterChangeListener mAdapterChangeListener;
+    private PageTransformer mPageTransformer;
+
+    private static final int DRAW_ORDER_DEFAULT = 0;
+    private static final int DRAW_ORDER_FORWARD = 1;
+    private static final int DRAW_ORDER_REVERSE = 2;
+    private int mDrawingOrder;
+    private ArrayList<View> mDrawingOrderedChildren;
+    private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator();
+
+    /**
+     * Indicates that the pager is in an idle, settled state. The current page
+     * is fully in view and no animation is in progress.
+     */
+    public static final int SCROLL_STATE_IDLE = 0;
+
+    /**
+     * Indicates that the pager is currently being dragged by the user.
+     */
+    public static final int SCROLL_STATE_DRAGGING = 1;
+
+    /**
+     * Indicates that the pager is in the process of settling to a final position.
+     */
+    public static final int SCROLL_STATE_SETTLING = 2;
+
+    private final Runnable mEndScrollRunnable = new Runnable() {
+        public void run() {
+            setScrollState(SCROLL_STATE_IDLE);
+            populate();
+        }
+    };
+
+    private int mScrollState = SCROLL_STATE_IDLE;
+
+    /**
+     * Callback interface for responding to changing state of the selected page.
+     */
+    public interface OnPageChangeListener {
+
+        /**
+         * This method will be invoked when the current page is scrolled, either as part
+         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
+         *
+         * @param position Position index of the first page currently being displayed.
+         *                 Page position+1 will be visible if positionOffset is nonzero.
+         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
+         * @param positionOffsetPixels Value in pixels indicating the offset from position.
+         */
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
+
+        /**
+         * This method will be invoked when a new page becomes selected. Animation is not
+         * necessarily complete.
+         *
+         * @param position Position index of the new selected page.
+         */
+        public void onPageSelected(int position);
+
+        /**
+         * Called when the scroll state changes. Useful for discovering when the user
+         * begins dragging, when the pager is automatically settling to the current page,
+         * or when it is fully stopped/idle.
+         *
+         * @param state The new scroll state.
+         * @see com.android.internal.widget.ViewPager#SCROLL_STATE_IDLE
+         * @see com.android.internal.widget.ViewPager#SCROLL_STATE_DRAGGING
+         * @see com.android.internal.widget.ViewPager#SCROLL_STATE_SETTLING
+         */
+        public void onPageScrollStateChanged(int state);
+    }
+
+    /**
+     * Simple implementation of the {@link OnPageChangeListener} interface with stub
+     * implementations of each method. Extend this if you do not intend to override
+     * every method of {@link OnPageChangeListener}.
+     */
+    public static class SimpleOnPageChangeListener implements OnPageChangeListener {
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            // This space for rent
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            // This space for rent
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            // This space for rent
+        }
+    }
+
+    /**
+     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
+     * This offers an opportunity for the application to apply a custom transformation
+     * to the page views using animation properties.
+     *
+     * <p>As property animation is only supported as of Android 3.0 and forward,
+     * setting a PageTransformer on a ViewPager on earlier platform versions will
+     * be ignored.</p>
+     */
+    public interface PageTransformer {
+        /**
+         * Apply a property transformation to the given page.
+         *
+         * @param page Apply the transformation to this page
+         * @param position Position of page relative to the current front-and-center
+         *                 position of the pager. 0 is front and center. 1 is one full
+         *                 page position to the right, and -1 is one page position to the left.
+         */
+        public void transformPage(View page, float position);
+    }
+
+    /**
+     * Used internally to monitor when adapters are switched.
+     */
+    interface OnAdapterChangeListener {
+        public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter);
+    }
+
+    /**
+     * Used internally to tag special types of child views that should be added as
+     * pager decorations by default.
+     */
+    interface Decor {}
+
+    public ViewPager(Context context) {
+        super(context);
+        initViewPager();
+    }
+
+    public ViewPager(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initViewPager();
+    }
+
+    void initViewPager() {
+        setWillNotDraw(false);
+        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+        setFocusable(true);
+        final Context context = getContext();
+        mScroller = new Scroller(context, sInterpolator);
+        final ViewConfiguration configuration = ViewConfiguration.get(context);
+        final float density = context.getResources().getDisplayMetrics().density;
+
+        mTouchSlop = configuration.getScaledPagingTouchSlop();
+        mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+        mLeftEdge = new EdgeEffect(context);
+        mRightEdge = new EdgeEffect(context);
+
+        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
+        mCloseEnough = (int) (CLOSE_ENOUGH * density);
+        mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);
+
+        setAccessibilityDelegate(new MyAccessibilityDelegate());
+
+        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        removeCallbacks(mEndScrollRunnable);
+        super.onDetachedFromWindow();
+    }
+
+    private void setScrollState(int newState) {
+        if (mScrollState == newState) {
+            return;
+        }
+
+        mScrollState = newState;
+        if (mPageTransformer != null) {
+            // PageTransformers can do complex things that benefit from hardware layers.
+            enableLayers(newState != SCROLL_STATE_IDLE);
+        }
+        if (mOnPageChangeListener != null) {
+            mOnPageChangeListener.onPageScrollStateChanged(newState);
+        }
+    }
+
+    /**
+     * Set a PagerAdapter that will supply views for this pager as needed.
+     *
+     * @param adapter Adapter to use
+     */
+    public void setAdapter(PagerAdapter adapter) {
+        if (mAdapter != null) {
+            mAdapter.unregisterDataSetObserver(mObserver);
+            mAdapter.startUpdate(this);
+            for (int i = 0; i < mItems.size(); i++) {
+                final ItemInfo ii = mItems.get(i);
+                mAdapter.destroyItem(this, ii.position, ii.object);
+            }
+            mAdapter.finishUpdate(this);
+            mItems.clear();
+            removeNonDecorViews();
+            mCurItem = 0;
+            scrollTo(0, 0);
+        }
+
+        final PagerAdapter oldAdapter = mAdapter;
+        mAdapter = adapter;
+        mExpectedAdapterCount = 0;
+
+        if (mAdapter != null) {
+            if (mObserver == null) {
+                mObserver = new PagerObserver();
+            }
+            mAdapter.registerDataSetObserver(mObserver);
+            mPopulatePending = false;
+            final boolean wasFirstLayout = mFirstLayout;
+            mFirstLayout = true;
+            mExpectedAdapterCount = mAdapter.getCount();
+            if (mRestoredCurItem >= 0) {
+                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
+                setCurrentItemInternal(mRestoredCurItem, false, true);
+                mRestoredCurItem = -1;
+                mRestoredAdapterState = null;
+                mRestoredClassLoader = null;
+            } else if (!wasFirstLayout) {
+                populate();
+            } else {
+                requestLayout();
+            }
+        }
+
+        if (mAdapterChangeListener != null && oldAdapter != adapter) {
+            mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
+        }
+    }
+
+    private void removeNonDecorViews() {
+        for (int i = 0; i < getChildCount(); i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (!lp.isDecor) {
+                removeViewAt(i);
+                i--;
+            }
+        }
+    }
+
+    /**
+     * Retrieve the current adapter supplying pages.
+     *
+     * @return The currently registered PagerAdapter
+     */
+    public PagerAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    void setOnAdapterChangeListener(OnAdapterChangeListener listener) {
+        mAdapterChangeListener = listener;
+    }
+
+    private int getClientWidth() {
+        return getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
+    }
+
+    /**
+     * Set the currently selected page. If the ViewPager has already been through its first
+     * layout with its current adapter there will be a smooth animated transition between
+     * the current item and the specified item.
+     *
+     * @param item Item index to select
+     */
+    public void setCurrentItem(int item) {
+        mPopulatePending = false;
+        setCurrentItemInternal(item, !mFirstLayout, false);
+    }
+
+    /**
+     * Set the currently selected page.
+     *
+     * @param item Item index to select
+     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
+     */
+    public void setCurrentItem(int item, boolean smoothScroll) {
+        mPopulatePending = false;
+        setCurrentItemInternal(item, smoothScroll, false);
+    }
+
+    public int getCurrentItem() {
+        return mCurItem;
+    }
+
+    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
+        setCurrentItemInternal(item, smoothScroll, always, 0);
+    }
+
+    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
+        if (mAdapter == null || mAdapter.getCount() <= 0) {
+            setScrollingCacheEnabled(false);
+            return;
+        }
+        if (!always && mCurItem == item && mItems.size() != 0) {
+            setScrollingCacheEnabled(false);
+            return;
+        }
+
+        if (item < 0) {
+            item = 0;
+        } else if (item >= mAdapter.getCount()) {
+            item = mAdapter.getCount() - 1;
+        }
+        final int pageLimit = mOffscreenPageLimit;
+        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
+            // We are doing a jump by more than one page.  To avoid
+            // glitches, we want to keep all current pages in the view
+            // until the scroll ends.
+            for (int i=0; i<mItems.size(); i++) {
+                mItems.get(i).scrolling = true;
+            }
+        }
+        final boolean dispatchSelected = mCurItem != item;
+
+        if (mFirstLayout) {
+            // We don't have any idea how big we are yet and shouldn't have any pages either.
+            // Just set things up and let the pending layout handle things.
+            mCurItem = item;
+            if (dispatchSelected && mOnPageChangeListener != null) {
+                mOnPageChangeListener.onPageSelected(item);
+            }
+            if (dispatchSelected && mInternalPageChangeListener != null) {
+                mInternalPageChangeListener.onPageSelected(item);
+            }
+            requestLayout();
+        } else {
+            populate(item);
+            scrollToItem(item, smoothScroll, velocity, dispatchSelected);
+        }
+    }
+
+    private void scrollToItem(int item, boolean smoothScroll, int velocity,
+            boolean dispatchSelected) {
+        final ItemInfo curInfo = infoForPosition(item);
+        int destX = 0;
+        if (curInfo != null) {
+            final int width = getClientWidth();
+            destX = (int) (width * Math.max(mFirstOffset,
+                    Math.min(curInfo.offset, mLastOffset)));
+        }
+        if (smoothScroll) {
+            smoothScrollTo(destX, 0, velocity);
+            if (dispatchSelected && mOnPageChangeListener != null) {
+                mOnPageChangeListener.onPageSelected(item);
+            }
+            if (dispatchSelected && mInternalPageChangeListener != null) {
+                mInternalPageChangeListener.onPageSelected(item);
+            }
+        } else {
+            if (dispatchSelected && mOnPageChangeListener != null) {
+                mOnPageChangeListener.onPageSelected(item);
+            }
+            if (dispatchSelected && mInternalPageChangeListener != null) {
+                mInternalPageChangeListener.onPageSelected(item);
+            }
+            completeScroll(false);
+            scrollTo(destX, 0);
+            pageScrolled(destX);
+        }
+    }
+
+    /**
+     * Set a listener that will be invoked whenever the page changes or is incrementally
+     * scrolled. See {@link OnPageChangeListener}.
+     *
+     * @param listener Listener to set
+     */
+    public void setOnPageChangeListener(OnPageChangeListener listener) {
+        mOnPageChangeListener = listener;
+    }
+
+    /**
+     * Set a {@link PageTransformer} that will be called for each attached page whenever
+     * the scroll position is changed. This allows the application to apply custom property
+     * transformations to each page, overriding the default sliding look and feel.
+     *
+     * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist.
+     * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p>
+     *
+     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
+     *                            to be drawn from last to first instead of first to last.
+     * @param transformer PageTransformer that will modify each page's animation properties
+     */
+    public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
+        final boolean hasTransformer = transformer != null;
+        final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
+        mPageTransformer = transformer;
+        setChildrenDrawingOrderEnabled(hasTransformer);
+        if (hasTransformer) {
+            mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
+        } else {
+            mDrawingOrder = DRAW_ORDER_DEFAULT;
+        }
+        if (needsPopulate) populate();
+    }
+
+    @Override
+    protected int getChildDrawingOrder(int childCount, int i) {
+        final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i;
+        final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex;
+        return result;
+    }
+
+    /**
+     * Set a separate OnPageChangeListener for internal use by the support library.
+     *
+     * @param listener Listener to set
+     * @return The old listener that was set, if any.
+     */
+    OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {
+        OnPageChangeListener oldListener = mInternalPageChangeListener;
+        mInternalPageChangeListener = listener;
+        return oldListener;
+    }
+
+    /**
+     * Returns the number of pages that will be retained to either side of the
+     * current page in the view hierarchy in an idle state. Defaults to 1.
+     *
+     * @return How many pages will be kept offscreen on either side
+     * @see #setOffscreenPageLimit(int)
+     */
+    public int getOffscreenPageLimit() {
+        return mOffscreenPageLimit;
+    }
+
+    /**
+     * Set the number of pages that should be retained to either side of the
+     * current page in the view hierarchy in an idle state. Pages beyond this
+     * limit will be recreated from the adapter when needed.
+     *
+     * <p>This is offered as an optimization. If you know in advance the number
+     * of pages you will need to support or have lazy-loading mechanisms in place
+     * on your pages, tweaking this setting can have benefits in perceived smoothness
+     * of paging animations and interaction. If you have a small number of pages (3-4)
+     * that you can keep active all at once, less time will be spent in layout for
+     * newly created view subtrees as the user pages back and forth.</p>
+     *
+     * <p>You should keep this limit low, especially if your pages have complex layouts.
+     * This setting defaults to 1.</p>
+     *
+     * @param limit How many pages will be kept offscreen in an idle state.
+     */
+    public void setOffscreenPageLimit(int limit) {
+        if (limit < DEFAULT_OFFSCREEN_PAGES) {
+            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
+                    DEFAULT_OFFSCREEN_PAGES);
+            limit = DEFAULT_OFFSCREEN_PAGES;
+        }
+        if (limit != mOffscreenPageLimit) {
+            mOffscreenPageLimit = limit;
+            populate();
+        }
+    }
+
+    /**
+     * Set the margin between pages.
+     *
+     * @param marginPixels Distance between adjacent pages in pixels
+     * @see #getPageMargin()
+     * @see #setPageMarginDrawable(android.graphics.drawable.Drawable)
+     * @see #setPageMarginDrawable(int)
+     */
+    public void setPageMargin(int marginPixels) {
+        final int oldMargin = mPageMargin;
+        mPageMargin = marginPixels;
+
+        final int width = getWidth();
+        recomputeScrollPosition(width, width, marginPixels, oldMargin);
+
+        requestLayout();
+    }
+
+    /**
+     * Return the margin between pages.
+     *
+     * @return The size of the margin in pixels
+     */
+    public int getPageMargin() {
+        return mPageMargin;
+    }
+
+    /**
+     * Set a drawable that will be used to fill the margin between pages.
+     *
+     * @param d Drawable to display between pages
+     */
+    public void setPageMarginDrawable(Drawable d) {
+        mMarginDrawable = d;
+        if (d != null) refreshDrawableState();
+        setWillNotDraw(d == null);
+        invalidate();
+    }
+
+    /**
+     * Set a drawable that will be used to fill the margin between pages.
+     *
+     * @param resId Resource ID of a drawable to display between pages
+     */
+    public void setPageMarginDrawable(@DrawableRes int resId) {
+        setPageMarginDrawable(getContext().getDrawable(resId));
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mMarginDrawable;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        final Drawable d = mMarginDrawable;
+        if (d != null && d.isStateful()) {
+            d.setState(getDrawableState());
+        }
+    }
+
+    // We want the duration of the page snap animation to be influenced by the distance that
+    // the screen has to travel, however, we don't want this duration to be effected in a
+    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
+    // of travel has on the overall snap duration.
+    float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    /**
+     * Like {@link android.view.View#scrollBy}, but scroll smoothly instead of immediately.
+     *
+     * @param x the number of pixels to scroll by on the X axis
+     * @param y the number of pixels to scroll by on the Y axis
+     */
+    void smoothScrollTo(int x, int y) {
+        smoothScrollTo(x, y, 0);
+    }
+
+    /**
+     * Like {@link android.view.View#scrollBy}, but scroll smoothly instead of immediately.
+     *
+     * @param x the number of pixels to scroll by on the X axis
+     * @param y the number of pixels to scroll by on the Y axis
+     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
+     */
+    void smoothScrollTo(int x, int y, int velocity) {
+        if (getChildCount() == 0) {
+            // Nothing to do.
+            setScrollingCacheEnabled(false);
+            return;
+        }
+        int sx = getScrollX();
+        int sy = getScrollY();
+        int dx = x - sx;
+        int dy = y - sy;
+        if (dx == 0 && dy == 0) {
+            completeScroll(false);
+            populate();
+            setScrollState(SCROLL_STATE_IDLE);
+            return;
+        }
+
+        setScrollingCacheEnabled(true);
+        setScrollState(SCROLL_STATE_SETTLING);
+
+        final int width = getClientWidth();
+        final int halfWidth = width / 2;
+        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
+        final float distance = halfWidth + halfWidth *
+                distanceInfluenceForSnapDuration(distanceRatio);
+
+        int duration = 0;
+        velocity = Math.abs(velocity);
+        if (velocity > 0) {
+            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        } else {
+            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
+            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
+            duration = (int) ((pageDelta + 1) * 100);
+        }
+        duration = Math.min(duration, MAX_SETTLE_DURATION);
+
+        mScroller.startScroll(sx, sy, dx, dy, duration);
+        postInvalidateOnAnimation();
+    }
+
+    ItemInfo addNewItem(int position, int index) {
+        ItemInfo ii = new ItemInfo();
+        ii.position = position;
+        ii.object = mAdapter.instantiateItem(this, position);
+        ii.widthFactor = mAdapter.getPageWidth(position);
+        if (index < 0 || index >= mItems.size()) {
+            mItems.add(ii);
+        } else {
+            mItems.add(index, ii);
+        }
+        return ii;
+    }
+
+    void dataSetChanged() {
+        // This method only gets called if our observer is attached, so mAdapter is non-null.
+
+        final int adapterCount = mAdapter.getCount();
+        mExpectedAdapterCount = adapterCount;
+        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 &&
+                mItems.size() < adapterCount;
+        int newCurrItem = mCurItem;
+
+        boolean isUpdating = false;
+        for (int i = 0; i < mItems.size(); i++) {
+            final ItemInfo ii = mItems.get(i);
+            final int newPos = mAdapter.getItemPosition(ii.object);
+
+            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
+                continue;
+            }
+
+            if (newPos == PagerAdapter.POSITION_NONE) {
+                mItems.remove(i);
+                i--;
+
+                if (!isUpdating) {
+                    mAdapter.startUpdate(this);
+                    isUpdating = true;
+                }
+
+                mAdapter.destroyItem(this, ii.position, ii.object);
+                needPopulate = true;
+
+                if (mCurItem == ii.position) {
+                    // Keep the current item in the valid range
+                    newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
+                    needPopulate = true;
+                }
+                continue;
+            }
+
+            if (ii.position != newPos) {
+                if (ii.position == mCurItem) {
+                    // Our current item changed position. Follow it.
+                    newCurrItem = newPos;
+                }
+
+                ii.position = newPos;
+                needPopulate = true;
+            }
+        }
+
+        if (isUpdating) {
+            mAdapter.finishUpdate(this);
+        }
+
+        Collections.sort(mItems, COMPARATOR);
+
+        if (needPopulate) {
+            // Reset our known page widths; populate will recompute them.
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (!lp.isDecor) {
+                    lp.widthFactor = 0.f;
+                }
+            }
+
+            setCurrentItemInternal(newCurrItem, false, true);
+            requestLayout();
+        }
+    }
+
+    void populate() {
+        populate(mCurItem);
+    }
+
+    void populate(int newCurrentItem) {
+        ItemInfo oldCurInfo = null;
+        int focusDirection = View.FOCUS_FORWARD;
+        if (mCurItem != newCurrentItem) {
+            focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
+            oldCurInfo = infoForPosition(mCurItem);
+            mCurItem = newCurrentItem;
+        }
+
+        if (mAdapter == null) {
+            sortChildDrawingOrder();
+            return;
+        }
+
+        // Bail now if we are waiting to populate.  This is to hold off
+        // on creating views from the time the user releases their finger to
+        // fling to a new position until we have finished the scroll to
+        // that position, avoiding glitches from happening at that point.
+        if (mPopulatePending) {
+            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
+            sortChildDrawingOrder();
+            return;
+        }
+
+        // Also, don't populate until we are attached to a window.  This is to
+        // avoid trying to populate before we have restored our view hierarchy
+        // state and conflicting with what is restored.
+        if (getWindowToken() == null) {
+            return;
+        }
+
+        mAdapter.startUpdate(this);
+
+        final int pageLimit = mOffscreenPageLimit;
+        final int startPos = Math.max(0, mCurItem - pageLimit);
+        final int N = mAdapter.getCount();
+        final int endPos = Math.min(N-1, mCurItem + pageLimit);
+
+        if (N != mExpectedAdapterCount) {
+            String resName;
+            try {
+                resName = getResources().getResourceName(getId());
+            } catch (Resources.NotFoundException e) {
+                resName = Integer.toHexString(getId());
+            }
+            throw new IllegalStateException("The application's PagerAdapter changed the adapter's" +
+                    " contents without calling PagerAdapter#notifyDataSetChanged!" +
+                    " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N +
+                    " Pager id: " + resName +
+                    " Pager class: " + getClass() +
+                    " Problematic adapter: " + mAdapter.getClass());
+        }
+
+        // Locate the currently focused item or add it if needed.
+        int curIndex = -1;
+        ItemInfo curItem = null;
+        for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
+            final ItemInfo ii = mItems.get(curIndex);
+            if (ii.position >= mCurItem) {
+                if (ii.position == mCurItem) curItem = ii;
+                break;
+            }
+        }
+
+        if (curItem == null && N > 0) {
+            curItem = addNewItem(mCurItem, curIndex);
+        }
+
+        // Fill 3x the available width or up to the number of offscreen
+        // pages requested to either side, whichever is larger.
+        // If we have no current item we have no work to do.
+        if (curItem != null) {
+            float extraWidthLeft = 0.f;
+            int itemIndex = curIndex - 1;
+            ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+            final int clientWidth = getClientWidth();
+            final float leftWidthNeeded = clientWidth <= 0 ? 0 :
+                    2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
+            for (int pos = mCurItem - 1; pos >= 0; pos--) {
+                if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
+                    if (ii == null) {
+                        break;
+                    }
+                    if (pos == ii.position && !ii.scrolling) {
+                        mItems.remove(itemIndex);
+                        mAdapter.destroyItem(this, pos, ii.object);
+                        if (DEBUG) {
+                            Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
+                                    " view: " + ((View) ii.object));
+                        }
+                        itemIndex--;
+                        curIndex--;
+                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                    }
+                } else if (ii != null && pos == ii.position) {
+                    extraWidthLeft += ii.widthFactor;
+                    itemIndex--;
+                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                } else {
+                    ii = addNewItem(pos, itemIndex + 1);
+                    extraWidthLeft += ii.widthFactor;
+                    curIndex++;
+                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                }
+            }
+
+            float extraWidthRight = curItem.widthFactor;
+            itemIndex = curIndex + 1;
+            if (extraWidthRight < 2.f) {
+                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                final float rightWidthNeeded = clientWidth <= 0 ? 0 :
+                        (float) getPaddingRight() / (float) clientWidth + 2.f;
+                for (int pos = mCurItem + 1; pos < N; pos++) {
+                    if (extraWidthRight >= rightWidthNeeded && pos > endPos) {
+                        if (ii == null) {
+                            break;
+                        }
+                        if (pos == ii.position && !ii.scrolling) {
+                            mItems.remove(itemIndex);
+                            mAdapter.destroyItem(this, pos, ii.object);
+                            if (DEBUG) {
+                                Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
+                                        " view: " + ((View) ii.object));
+                            }
+                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                        }
+                    } else if (ii != null && pos == ii.position) {
+                        extraWidthRight += ii.widthFactor;
+                        itemIndex++;
+                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                    } else {
+                        ii = addNewItem(pos, itemIndex);
+                        itemIndex++;
+                        extraWidthRight += ii.widthFactor;
+                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                    }
+                }
+            }
+
+            calculatePageOffsets(curItem, curIndex, oldCurInfo);
+        }
+
+        if (DEBUG) {
+            Log.i(TAG, "Current page list:");
+            for (int i=0; i<mItems.size(); i++) {
+                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
+            }
+        }
+
+        mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
+
+        mAdapter.finishUpdate(this);
+
+        // Check width measurement of current pages and drawing sort order.
+        // Update LayoutParams as needed.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            lp.childIndex = i;
+            if (!lp.isDecor && lp.widthFactor == 0.f) {
+                // 0 means requery the adapter for this, it doesn't have a valid width.
+                final ItemInfo ii = infoForChild(child);
+                if (ii != null) {
+                    lp.widthFactor = ii.widthFactor;
+                    lp.position = ii.position;
+                }
+            }
+        }
+        sortChildDrawingOrder();
+
+        if (hasFocus()) {
+            View currentFocused = findFocus();
+            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
+            if (ii == null || ii.position != mCurItem) {
+                for (int i=0; i<getChildCount(); i++) {
+                    View child = getChildAt(i);
+                    ii = infoForChild(child);
+                    if (ii != null && ii.position == mCurItem) {
+                        if (child.requestFocus(focusDirection)) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void sortChildDrawingOrder() {
+        if (mDrawingOrder != DRAW_ORDER_DEFAULT) {
+            if (mDrawingOrderedChildren == null) {
+                mDrawingOrderedChildren = new ArrayList<View>();
+            } else {
+                mDrawingOrderedChildren.clear();
+            }
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                mDrawingOrderedChildren.add(child);
+            }
+            Collections.sort(mDrawingOrderedChildren, sPositionComparator);
+        }
+    }
+
+    private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) {
+        final int N = mAdapter.getCount();
+        final int width = getClientWidth();
+        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
+        // Fix up offsets for later layout.
+        if (oldCurInfo != null) {
+            final int oldCurPosition = oldCurInfo.position;
+            // Base offsets off of oldCurInfo.
+            if (oldCurPosition < curItem.position) {
+                int itemIndex = 0;
+                ItemInfo ii = null;
+                float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset;
+                for (int pos = oldCurPosition + 1;
+                        pos <= curItem.position && itemIndex < mItems.size(); pos++) {
+                    ii = mItems.get(itemIndex);
+                    while (pos > ii.position && itemIndex < mItems.size() - 1) {
+                        itemIndex++;
+                        ii = mItems.get(itemIndex);
+                    }
+                    while (pos < ii.position) {
+                        // We don't have an item populated for this,
+                        // ask the adapter for an offset.
+                        offset += mAdapter.getPageWidth(pos) + marginOffset;
+                        pos++;
+                    }
+                    ii.offset = offset;
+                    offset += ii.widthFactor + marginOffset;
+                }
+            } else if (oldCurPosition > curItem.position) {
+                int itemIndex = mItems.size() - 1;
+                ItemInfo ii = null;
+                float offset = oldCurInfo.offset;
+                for (int pos = oldCurPosition - 1;
+                        pos >= curItem.position && itemIndex >= 0; pos--) {
+                    ii = mItems.get(itemIndex);
+                    while (pos < ii.position && itemIndex > 0) {
+                        itemIndex--;
+                        ii = mItems.get(itemIndex);
+                    }
+                    while (pos > ii.position) {
+                        // We don't have an item populated for this,
+                        // ask the adapter for an offset.
+                        offset -= mAdapter.getPageWidth(pos) + marginOffset;
+                        pos--;
+                    }
+                    offset -= ii.widthFactor + marginOffset;
+                    ii.offset = offset;
+                }
+            }
+        }
+
+        // Base all offsets off of curItem.
+        final int itemCount = mItems.size();
+        float offset = curItem.offset;
+        int pos = curItem.position - 1;
+        mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE;
+        mLastOffset = curItem.position == N - 1 ?
+                curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE;
+        // Previous pages
+        for (int i = curIndex - 1; i >= 0; i--, pos--) {
+            final ItemInfo ii = mItems.get(i);
+            while (pos > ii.position) {
+                offset -= mAdapter.getPageWidth(pos--) + marginOffset;
+            }
+            offset -= ii.widthFactor + marginOffset;
+            ii.offset = offset;
+            if (ii.position == 0) mFirstOffset = offset;
+        }
+        offset = curItem.offset + curItem.widthFactor + marginOffset;
+        pos = curItem.position + 1;
+        // Next pages
+        for (int i = curIndex + 1; i < itemCount; i++, pos++) {
+            final ItemInfo ii = mItems.get(i);
+            while (pos < ii.position) {
+                offset += mAdapter.getPageWidth(pos++) + marginOffset;
+            }
+            if (ii.position == N - 1) {
+                mLastOffset = offset + ii.widthFactor - 1;
+            }
+            ii.offset = offset;
+            offset += ii.widthFactor + marginOffset;
+        }
+
+        mNeedCalculatePageOffsets = false;
+    }
+
+    /**
+     * This is the persistent state that is saved by ViewPager.  Only needed
+     * if you are creating a sublass of ViewPager that must save its own
+     * state, in which case it should implement a subclass of this which
+     * contains that state.
+     */
+    public static class SavedState extends BaseSavedState {
+        int position;
+        Parcelable adapterState;
+        ClassLoader loader;
+
+        public SavedState(Parcel source) {
+            super(source);
+        }
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(position);
+            out.writeParcelable(adapterState, flags);
+        }
+
+        @Override
+        public String toString() {
+            return "FragmentPager.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " position=" + position + "}";
+        }
+
+        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+
+        SavedState(Parcel in, ClassLoader loader) {
+            super(in);
+            if (loader == null) {
+                loader = getClass().getClassLoader();
+            }
+            position = in.readInt();
+            adapterState = in.readParcelable(loader);
+            this.loader = loader;
+        }
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.position = mCurItem;
+        if (mAdapter != null) {
+            ss.adapterState = mAdapter.saveState();
+        }
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        SavedState ss = (SavedState)state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (mAdapter != null) {
+            mAdapter.restoreState(ss.adapterState, ss.loader);
+            setCurrentItemInternal(ss.position, false, true);
+        } else {
+            mRestoredCurItem = ss.position;
+            mRestoredAdapterState = ss.adapterState;
+            mRestoredClassLoader = ss.loader;
+        }
+    }
+
+    @Override
+    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+        if (!checkLayoutParams(params)) {
+            params = generateLayoutParams(params);
+        }
+        final LayoutParams lp = (LayoutParams) params;
+        lp.isDecor |= child instanceof Decor;
+        if (mInLayout) {
+            if (lp != null && lp.isDecor) {
+                throw new IllegalStateException("Cannot add pager decor view during layout");
+            }
+            lp.needsMeasure = true;
+            addViewInLayout(child, index, params);
+        } else {
+            super.addView(child, index, params);
+        }
+
+        if (USE_CACHE) {
+            if (child.getVisibility() != GONE) {
+                child.setDrawingCacheEnabled(mScrollingCacheEnabled);
+            } else {
+                child.setDrawingCacheEnabled(false);
+            }
+        }
+    }
+
+    @Override
+    public void removeView(View view) {
+        if (mInLayout) {
+            removeViewInLayout(view);
+        } else {
+            super.removeView(view);
+        }
+    }
+
+    ItemInfo infoForChild(View child) {
+        for (int i=0; i<mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (mAdapter.isViewFromObject(child, ii.object)) {
+                return ii;
+            }
+        }
+        return null;
+    }
+
+    ItemInfo infoForAnyChild(View child) {
+        ViewParent parent;
+        while ((parent=child.getParent()) != this) {
+            if (parent == null || !(parent instanceof View)) {
+                return null;
+            }
+            child = (View)parent;
+        }
+        return infoForChild(child);
+    }
+
+    ItemInfo infoForPosition(int position) {
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (ii.position == position) {
+                return ii;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mFirstLayout = true;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // For simple implementation, our internal size is always 0.
+        // We depend on the container to specify the layout size of
+        // our view.  We can't really know what it is since we will be
+        // adding and removing different arbitrary views and do not
+        // want the layout to change as this happens.
+        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
+                getDefaultSize(0, heightMeasureSpec));
+
+        final int measuredWidth = getMeasuredWidth();
+        final int maxGutterSize = measuredWidth / 10;
+        mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
+
+        // Children are just made to fill our space.
+        int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
+        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
+
+        /*
+         * Make sure all children have been properly measured. Decor views first.
+         * Right now we cheat and make this less complicated by assuming decor
+         * views won't intersect. We will pin to edges based on gravity.
+         */
+        int size = getChildCount();
+        for (int i = 0; i < size; ++i) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp != null && lp.isDecor) {
+                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+                    int widthMode = MeasureSpec.AT_MOST;
+                    int heightMode = MeasureSpec.AT_MOST;
+                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
+                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
+
+                    if (consumeVertical) {
+                        widthMode = MeasureSpec.EXACTLY;
+                    } else if (consumeHorizontal) {
+                        heightMode = MeasureSpec.EXACTLY;
+                    }
+
+                    int widthSize = childWidthSize;
+                    int heightSize = childHeightSize;
+                    if (lp.width != LayoutParams.WRAP_CONTENT) {
+                        widthMode = MeasureSpec.EXACTLY;
+                        if (lp.width != LayoutParams.FILL_PARENT) {
+                            widthSize = lp.width;
+                        }
+                    }
+                    if (lp.height != LayoutParams.WRAP_CONTENT) {
+                        heightMode = MeasureSpec.EXACTLY;
+                        if (lp.height != LayoutParams.FILL_PARENT) {
+                            heightSize = lp.height;
+                        }
+                    }
+                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
+                    child.measure(widthSpec, heightSpec);
+
+                    if (consumeVertical) {
+                        childHeightSize -= child.getMeasuredHeight();
+                    } else if (consumeHorizontal) {
+                        childWidthSize -= child.getMeasuredWidth();
+                    }
+                }
+            }
+        }
+
+        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
+        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
+
+        // Make sure we have created all fragments that we need to have shown.
+        mInLayout = true;
+        populate();
+        mInLayout = false;
+
+        // Page views next.
+        size = getChildCount();
+        for (int i = 0; i < size; ++i) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child
+                        + ": " + mChildWidthMeasureSpec);
+
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp == null || !lp.isDecor) {
+                    final int widthSpec = MeasureSpec.makeMeasureSpec(
+                            (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
+                    child.measure(widthSpec, mChildHeightMeasureSpec);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        // Make sure scroll position is set correctly.
+        if (w != oldw) {
+            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);
+        }
+    }
+
+    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {
+        if (oldWidth > 0 && !mItems.isEmpty()) {
+            final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin;
+            final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight()
+                                           + oldMargin;
+            final int xpos = getScrollX();
+            final float pageOffset = (float) xpos / oldWidthWithMargin;
+            final int newOffsetPixels = (int) (pageOffset * widthWithMargin);
+
+            scrollTo(newOffsetPixels, getScrollY());
+            if (!mScroller.isFinished()) {
+                // We now return to your regularly scheduled scroll, already in progress.
+                final int newDuration = mScroller.getDuration() - mScroller.timePassed();
+                ItemInfo targetInfo = infoForPosition(mCurItem);
+                mScroller.startScroll(newOffsetPixels, 0,
+                        (int) (targetInfo.offset * width), 0, newDuration);
+            }
+        } else {
+            final ItemInfo ii = infoForPosition(mCurItem);
+            final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0;
+            final int scrollPos = (int) (scrollOffset *
+                                         (width - getPaddingLeft() - getPaddingRight()));
+            if (scrollPos != getScrollX()) {
+                completeScroll(false);
+                scrollTo(scrollPos, getScrollY());
+            }
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int count = getChildCount();
+        int width = r - l;
+        int height = b - t;
+        int paddingLeft = getPaddingLeft();
+        int paddingTop = getPaddingTop();
+        int paddingRight = getPaddingRight();
+        int paddingBottom = getPaddingBottom();
+        final int scrollX = getScrollX();
+
+        int decorCount = 0;
+
+        // First pass - decor views. We need to do this in two passes so that
+        // we have the proper offsets for non-decor views later.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                int childLeft = 0;
+                int childTop = 0;
+                if (lp.isDecor) {
+                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+                    switch (hgrav) {
+                        default:
+                            childLeft = paddingLeft;
+                            break;
+                        case Gravity.LEFT:
+                            childLeft = paddingLeft;
+                            paddingLeft += child.getMeasuredWidth();
+                            break;
+                        case Gravity.CENTER_HORIZONTAL:
+                            childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
+                                    paddingLeft);
+                            break;
+                        case Gravity.RIGHT:
+                            childLeft = width - paddingRight - child.getMeasuredWidth();
+                            paddingRight += child.getMeasuredWidth();
+                            break;
+                    }
+                    switch (vgrav) {
+                        default:
+                            childTop = paddingTop;
+                            break;
+                        case Gravity.TOP:
+                            childTop = paddingTop;
+                            paddingTop += child.getMeasuredHeight();
+                            break;
+                        case Gravity.CENTER_VERTICAL:
+                            childTop = Math.max((height - child.getMeasuredHeight()) / 2,
+                                    paddingTop);
+                            break;
+                        case Gravity.BOTTOM:
+                            childTop = height - paddingBottom - child.getMeasuredHeight();
+                            paddingBottom += child.getMeasuredHeight();
+                            break;
+                    }
+                    childLeft += scrollX;
+                    child.layout(childLeft, childTop,
+                            childLeft + child.getMeasuredWidth(),
+                            childTop + child.getMeasuredHeight());
+                    decorCount++;
+                }
+            }
+        }
+
+        final int childWidth = width - paddingLeft - paddingRight;
+        // Page views. Do this once we have the right padding offsets from above.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                ItemInfo ii;
+                if (!lp.isDecor && (ii = infoForChild(child)) != null) {
+                    int loff = (int) (childWidth * ii.offset);
+                    int childLeft = paddingLeft + loff;
+                    int childTop = paddingTop;
+                    if (lp.needsMeasure) {
+                        // This was added during layout and needs measurement.
+                        // Do it now that we know what we're working with.
+                        lp.needsMeasure = false;
+                        final int widthSpec = MeasureSpec.makeMeasureSpec(
+                                (int) (childWidth * lp.widthFactor),
+                                MeasureSpec.EXACTLY);
+                        final int heightSpec = MeasureSpec.makeMeasureSpec(
+                                (int) (height - paddingTop - paddingBottom),
+                                MeasureSpec.EXACTLY);
+                        child.measure(widthSpec, heightSpec);
+                    }
+                    if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object
+                            + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()
+                            + "x" + child.getMeasuredHeight());
+                    child.layout(childLeft, childTop,
+                            childLeft + child.getMeasuredWidth(),
+                            childTop + child.getMeasuredHeight());
+                }
+            }
+        }
+        mTopPageBounds = paddingTop;
+        mBottomPageBounds = height - paddingBottom;
+        mDecorChildCount = decorCount;
+
+        if (mFirstLayout) {
+            scrollToItem(mCurItem, false, 0, false);
+        }
+        mFirstLayout = false;
+    }
+
+    @Override
+    public void computeScroll() {
+        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
+            int oldX = getScrollX();
+            int oldY = getScrollY();
+            int x = mScroller.getCurrX();
+            int y = mScroller.getCurrY();
+
+            if (oldX != x || oldY != y) {
+                scrollTo(x, y);
+                if (!pageScrolled(x)) {
+                    mScroller.abortAnimation();
+                    scrollTo(0, y);
+                }
+            }
+
+            // Keep on drawing until the animation has finished.
+            postInvalidateOnAnimation();
+            return;
+        }
+
+        // Done with scroll, clean up state.
+        completeScroll(true);
+    }
+
+    private boolean pageScrolled(int xpos) {
+        if (mItems.size() == 0) {
+            mCalledSuper = false;
+            onPageScrolled(0, 0, 0);
+            if (!mCalledSuper) {
+                throw new IllegalStateException(
+                        "onPageScrolled did not call superclass implementation");
+            }
+            return false;
+        }
+        final ItemInfo ii = infoForCurrentScrollPosition();
+        final int width = getClientWidth();
+        final int widthWithMargin = width + mPageMargin;
+        final float marginOffset = (float) mPageMargin / width;
+        final int currentPage = ii.position;
+        final float pageOffset = (((float) xpos / width) - ii.offset) /
+                (ii.widthFactor + marginOffset);
+        final int offsetPixels = (int) (pageOffset * widthWithMargin);
+
+        mCalledSuper = false;
+        onPageScrolled(currentPage, pageOffset, offsetPixels);
+        if (!mCalledSuper) {
+            throw new IllegalStateException(
+                    "onPageScrolled did not call superclass implementation");
+        }
+        return true;
+    }
+
+    /**
+     * This method will be invoked when the current page is scrolled, either as part
+     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
+     * If you override this method you must call through to the superclass implementation
+     * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
+     * returns.
+     *
+     * @param position Position index of the first page currently being displayed.
+     *                 Page position+1 will be visible if positionOffset is nonzero.
+     * @param offset Value from [0, 1) indicating the offset from the page at position.
+     * @param offsetPixels Value in pixels indicating the offset from position.
+     */
+    protected void onPageScrolled(int position, float offset, int offsetPixels) {
+        // Offset any decor views if needed - keep them on-screen at all times.
+        if (mDecorChildCount > 0) {
+            final int scrollX = getScrollX();
+            int paddingLeft = getPaddingLeft();
+            int paddingRight = getPaddingRight();
+            final int width = getWidth();
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (!lp.isDecor) continue;
+
+                final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                int childLeft = 0;
+                switch (hgrav) {
+                    default:
+                        childLeft = paddingLeft;
+                        break;
+                    case Gravity.LEFT:
+                        childLeft = paddingLeft;
+                        paddingLeft += child.getWidth();
+                        break;
+                    case Gravity.CENTER_HORIZONTAL:
+                        childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
+                                paddingLeft);
+                        break;
+                    case Gravity.RIGHT:
+                        childLeft = width - paddingRight - child.getMeasuredWidth();
+                        paddingRight += child.getMeasuredWidth();
+                        break;
+                }
+                childLeft += scrollX;
+
+                final int childOffset = childLeft - child.getLeft();
+                if (childOffset != 0) {
+                    child.offsetLeftAndRight(childOffset);
+                }
+            }
+        }
+
+        if (mOnPageChangeListener != null) {
+            mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);
+        }
+        if (mInternalPageChangeListener != null) {
+            mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);
+        }
+
+        if (mPageTransformer != null) {
+            final int scrollX = getScrollX();
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                if (lp.isDecor) continue;
+
+                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
+                mPageTransformer.transformPage(child, transformPos);
+            }
+        }
+
+        mCalledSuper = true;
+    }
+
+    private void completeScroll(boolean postEvents) {
+        boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
+        if (needPopulate) {
+            // Done with scroll, no longer want to cache view drawing.
+            setScrollingCacheEnabled(false);
+            mScroller.abortAnimation();
+            int oldX = getScrollX();
+            int oldY = getScrollY();
+            int x = mScroller.getCurrX();
+            int y = mScroller.getCurrY();
+            if (oldX != x || oldY != y) {
+                scrollTo(x, y);
+            }
+        }
+        mPopulatePending = false;
+        for (int i=0; i<mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (ii.scrolling) {
+                needPopulate = true;
+                ii.scrolling = false;
+            }
+        }
+        if (needPopulate) {
+            if (postEvents) {
+                postOnAnimation(mEndScrollRunnable);
+            } else {
+                mEndScrollRunnable.run();
+            }
+        }
+    }
+
+    private boolean isGutterDrag(float x, float dx) {
+        return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0);
+    }
+
+    private void enableLayers(boolean enable) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final int layerType = enable ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE;
+            getChildAt(i).setLayerType(layerType, null);
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        /*
+         * This method JUST determines whether we want to intercept the motion.
+         * If we return true, onMotionEvent will be called and we do the actual
+         * scrolling there.
+         */
+
+        final int action = ev.getAction() & MotionEvent.ACTION_MASK;
+
+        // Always take care of the touch gesture being complete.
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+            // Release the drag.
+            if (DEBUG) Log.v(TAG, "Intercept done!");
+            mIsBeingDragged = false;
+            mIsUnableToDrag = false;
+            mActivePointerId = INVALID_POINTER;
+            if (mVelocityTracker != null) {
+                mVelocityTracker.recycle();
+                mVelocityTracker = null;
+            }
+            return false;
+        }
+
+        // Nothing more to do here if we have decided whether or not we
+        // are dragging.
+        if (action != MotionEvent.ACTION_DOWN) {
+            if (mIsBeingDragged) {
+                if (DEBUG) Log.v(TAG, "Intercept returning true!");
+                return true;
+            }
+            if (mIsUnableToDrag) {
+                if (DEBUG) Log.v(TAG, "Intercept returning false!");
+                return false;
+            }
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_MOVE: {
+                /*
+                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
+                 * whether the user has moved far enough from his original down touch.
+                 */
+
+                /*
+                * Locally do absolute value. mLastMotionY is set to the y value
+                * of the down event.
+                */
+                final int activePointerId = mActivePointerId;
+                if (activePointerId == INVALID_POINTER) {
+                    // If we don't have a valid id, the touch down wasn't on content.
+                    break;
+                }
+
+                final int pointerIndex = ev.findPointerIndex(activePointerId);
+                final float x = ev.getX(pointerIndex);
+                final float dx = x - mLastMotionX;
+                final float xDiff = Math.abs(dx);
+                final float y = ev.getY(pointerIndex);
+                final float yDiff = Math.abs(y - mInitialMotionY);
+                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
+
+                if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&
+                        canScroll(this, false, (int) dx, (int) x, (int) y)) {
+                    // Nested view has scrollable area under this point. Let it be handled there.
+                    mLastMotionX = x;
+                    mLastMotionY = y;
+                    mIsUnableToDrag = true;
+                    return false;
+                }
+                if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
+                    if (DEBUG) Log.v(TAG, "Starting drag!");
+                    mIsBeingDragged = true;
+                    requestParentDisallowInterceptTouchEvent(true);
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                    mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :
+                            mInitialMotionX - mTouchSlop;
+                    mLastMotionY = y;
+                    setScrollingCacheEnabled(true);
+                } else if (yDiff > mTouchSlop) {
+                    // The finger has moved enough in the vertical
+                    // direction to be counted as a drag...  abort
+                    // any attempt to drag horizontally, to work correctly
+                    // with children that have scrolling containers.
+                    if (DEBUG) Log.v(TAG, "Starting unable to drag!");
+                    mIsUnableToDrag = true;
+                }
+                if (mIsBeingDragged) {
+                    // Scroll to follow the motion event
+                    if (performDrag(x)) {
+                        postInvalidateOnAnimation();
+                    }
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_DOWN: {
+                /*
+                 * Remember location of down touch.
+                 * ACTION_DOWN always refers to pointer index 0.
+                 */
+                mLastMotionX = mInitialMotionX = ev.getX();
+                mLastMotionY = mInitialMotionY = ev.getY();
+                mActivePointerId = ev.getPointerId(0);
+                mIsUnableToDrag = false;
+
+                mScroller.computeScrollOffset();
+                if (mScrollState == SCROLL_STATE_SETTLING &&
+                        Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
+                    // Let the user 'catch' the pager as it animates.
+                    mScroller.abortAnimation();
+                    mPopulatePending = false;
+                    populate();
+                    mIsBeingDragged = true;
+                    requestParentDisallowInterceptTouchEvent(true);
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                } else {
+                    completeScroll(false);
+                    mIsBeingDragged = false;
+                }
+
+                if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
+                        + " mIsBeingDragged=" + mIsBeingDragged
+                        + "mIsUnableToDrag=" + mIsUnableToDrag);
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_UP:
+                onSecondaryPointerUp(ev);
+                break;
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        /*
+         * The only time we want to intercept motion events is if we are in the
+         * drag mode.
+         */
+        return mIsBeingDragged;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mFakeDragging) {
+            // A fake drag is in progress already, ignore this real one
+            // but still eat the touch events.
+            // (It is likely that the user is multi-touching the screen.)
+            return true;
+        }
+
+        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
+            // Don't handle edge touches immediately -- they may actually belong to one of our
+            // descendants.
+            return false;
+        }
+
+        if (mAdapter == null || mAdapter.getCount() == 0) {
+            // Nothing to present or scroll; nothing to touch.
+            return false;
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        final int action = ev.getAction();
+        boolean needsInvalidate = false;
+
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN: {
+                mScroller.abortAnimation();
+                mPopulatePending = false;
+                populate();
+
+                // Remember where the motion event started
+                mLastMotionX = mInitialMotionX = ev.getX();
+                mLastMotionY = mInitialMotionY = ev.getY();
+                mActivePointerId = ev.getPointerId(0);
+                break;
+            }
+            case MotionEvent.ACTION_MOVE:
+                if (!mIsBeingDragged) {
+                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(pointerIndex);
+                    final float xDiff = Math.abs(x - mLastMotionX);
+                    final float y = ev.getY(pointerIndex);
+                    final float yDiff = Math.abs(y - mLastMotionY);
+                    if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
+                    if (xDiff > mTouchSlop && xDiff > yDiff) {
+                        if (DEBUG) Log.v(TAG, "Starting drag!");
+                        mIsBeingDragged = true;
+                        requestParentDisallowInterceptTouchEvent(true);
+                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
+                                mInitialMotionX - mTouchSlop;
+                        mLastMotionY = y;
+                        setScrollState(SCROLL_STATE_DRAGGING);
+                        setScrollingCacheEnabled(true);
+
+                        // Disallow Parent Intercept, just in case
+                        ViewParent parent = getParent();
+                        if (parent != null) {
+                            parent.requestDisallowInterceptTouchEvent(true);
+                        }
+                    }
+                }
+                // Not else! Note that mIsBeingDragged can be set above.
+                if (mIsBeingDragged) {
+                    // Scroll to follow the motion event
+                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(activePointerIndex);
+                    needsInvalidate |= performDrag(x);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mIsBeingDragged) {
+                    final VelocityTracker velocityTracker = mVelocityTracker;
+                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                    int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
+                    mPopulatePending = true;
+                    final int width = getClientWidth();
+                    final int scrollX = getScrollX();
+                    final ItemInfo ii = infoForCurrentScrollPosition();
+                    final int currentPage = ii.position;
+                    final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
+                    final int activePointerIndex =
+                            ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(activePointerIndex);
+                    final int totalDelta = (int) (x - mInitialMotionX);
+                    int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
+                            totalDelta);
+                    setCurrentItemInternal(nextPage, true, true, initialVelocity);
+
+                    mActivePointerId = INVALID_POINTER;
+                    endDrag();
+                    mLeftEdge.onRelease();
+                    mRightEdge.onRelease();
+                    needsInvalidate = true;
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                if (mIsBeingDragged) {
+                    scrollToItem(mCurItem, true, 0, false);
+                    mActivePointerId = INVALID_POINTER;
+                    endDrag();
+                    mLeftEdge.onRelease();
+                    mRightEdge.onRelease();
+                    needsInvalidate = true;
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int index = ev.getActionIndex();
+                final float x = ev.getX(index);
+                mLastMotionX = x;
+                mActivePointerId = ev.getPointerId(index);
+                break;
+            }
+            case MotionEvent.ACTION_POINTER_UP:
+                onSecondaryPointerUp(ev);
+                mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
+                break;
+        }
+        if (needsInvalidate) {
+            postInvalidateOnAnimation();
+        }
+        return true;
+    }
+
+    private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        final ViewParent parent = getParent();
+        if (parent != null) {
+            parent.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+    }
+
+    private boolean performDrag(float x) {
+        boolean needsInvalidate = false;
+
+        final float deltaX = mLastMotionX - x;
+        mLastMotionX = x;
+
+        float oldScrollX = getScrollX();
+        float scrollX = oldScrollX + deltaX;
+        final int width = getClientWidth();
+
+        float leftBound = width * mFirstOffset;
+        float rightBound = width * mLastOffset;
+        boolean leftAbsolute = true;
+        boolean rightAbsolute = true;
+
+        final ItemInfo firstItem = mItems.get(0);
+        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+        if (firstItem.position != 0) {
+            leftAbsolute = false;
+            leftBound = firstItem.offset * width;
+        }
+        if (lastItem.position != mAdapter.getCount() - 1) {
+            rightAbsolute = false;
+            rightBound = lastItem.offset * width;
+        }
+
+        if (scrollX < leftBound) {
+            if (leftAbsolute) {
+                float over = leftBound - scrollX;
+                mLeftEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
+            }
+            scrollX = leftBound;
+        } else if (scrollX > rightBound) {
+            if (rightAbsolute) {
+                float over = scrollX - rightBound;
+                mRightEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
+            }
+            scrollX = rightBound;
+        }
+        // Don't lose the rounded component
+        mLastMotionX += scrollX - (int) scrollX;
+        scrollTo((int) scrollX, getScrollY());
+        pageScrolled((int) scrollX);
+
+        return needsInvalidate;
+    }
+
+    /**
+     * @return Info about the page at the current scroll position.
+     *         This can be synthetic for a missing middle page; the 'object' field can be null.
+     */
+    private ItemInfo infoForCurrentScrollPosition() {
+        final int width = getClientWidth();
+        final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
+        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
+        int lastPos = -1;
+        float lastOffset = 0.f;
+        float lastWidth = 0.f;
+        boolean first = true;
+
+        ItemInfo lastItem = null;
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            float offset;
+            if (!first && ii.position != lastPos + 1) {
+                // Create a synthetic item for a missing page.
+                ii = mTempItem;
+                ii.offset = lastOffset + lastWidth + marginOffset;
+                ii.position = lastPos + 1;
+                ii.widthFactor = mAdapter.getPageWidth(ii.position);
+                i--;
+            }
+            offset = ii.offset;
+
+            final float leftBound = offset;
+            final float rightBound = offset + ii.widthFactor + marginOffset;
+            if (first || scrollOffset >= leftBound) {
+                if (scrollOffset < rightBound || i == mItems.size() - 1) {
+                    return ii;
+                }
+            } else {
+                return lastItem;
+            }
+            first = false;
+            lastPos = ii.position;
+            lastOffset = offset;
+            lastWidth = ii.widthFactor;
+            lastItem = ii;
+        }
+
+        return lastItem;
+    }
+
+    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
+        int targetPage;
+        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
+            targetPage = velocity > 0 ? currentPage : currentPage + 1;
+        } else {
+            final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
+            targetPage = (int) (currentPage + pageOffset + truncator);
+        }
+
+        if (mItems.size() > 0) {
+            final ItemInfo firstItem = mItems.get(0);
+            final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+
+            // Only let the user target pages we have items for
+            targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
+        }
+
+        return targetPage;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        boolean needsInvalidate = false;
+
+        final int overScrollMode = getOverScrollMode();
+        if (overScrollMode == View.OVER_SCROLL_ALWAYS ||
+                (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS &&
+                        mAdapter != null && mAdapter.getCount() > 1)) {
+            if (!mLeftEdge.isFinished()) {
+                final int restoreCount = canvas.save();
+                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+                final int width = getWidth();
+
+                canvas.rotate(270);
+                canvas.translate(-height + getPaddingTop(), mFirstOffset * width);
+                mLeftEdge.setSize(height, width);
+                needsInvalidate |= mLeftEdge.draw(canvas);
+                canvas.restoreToCount(restoreCount);
+            }
+            if (!mRightEdge.isFinished()) {
+                final int restoreCount = canvas.save();
+                final int width = getWidth();
+                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+
+                canvas.rotate(90);
+                canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width);
+                mRightEdge.setSize(height, width);
+                needsInvalidate |= mRightEdge.draw(canvas);
+                canvas.restoreToCount(restoreCount);
+            }
+        } else {
+            mLeftEdge.finish();
+            mRightEdge.finish();
+        }
+
+        if (needsInvalidate) {
+            // Keep animating
+            postInvalidateOnAnimation();
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // Draw the margin drawable between pages if needed.
+        if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) {
+            final int scrollX = getScrollX();
+            final int width = getWidth();
+
+            final float marginOffset = (float) mPageMargin / width;
+            int itemIndex = 0;
+            ItemInfo ii = mItems.get(0);
+            float offset = ii.offset;
+            final int itemCount = mItems.size();
+            final int firstPos = ii.position;
+            final int lastPos = mItems.get(itemCount - 1).position;
+            for (int pos = firstPos; pos < lastPos; pos++) {
+                while (pos > ii.position && itemIndex < itemCount) {
+                    ii = mItems.get(++itemIndex);
+                }
+
+                float drawAt;
+                if (pos == ii.position) {
+                    drawAt = (ii.offset + ii.widthFactor) * width;
+                    offset = ii.offset + ii.widthFactor + marginOffset;
+                } else {
+                    float widthFactor = mAdapter.getPageWidth(pos);
+                    drawAt = (offset + widthFactor) * width;
+                    offset += widthFactor + marginOffset;
+                }
+
+                if (drawAt + mPageMargin > scrollX) {
+                    mMarginDrawable.setBounds((int) drawAt, mTopPageBounds,
+                            (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds);
+                    mMarginDrawable.draw(canvas);
+                }
+
+                if (drawAt > scrollX + width) {
+                    break; // No more visible, no sense in continuing
+                }
+            }
+        }
+    }
+
+    /**
+     * Start a fake drag of the pager.
+     *
+     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager
+     * with the touch scrolling of another view, while still letting the ViewPager
+     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)
+     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call
+     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.
+     *
+     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag
+     * is already in progress, this method will return false.
+     *
+     * @return true if the fake drag began successfully, false if it could not be started.
+     *
+     * @see #fakeDragBy(float)
+     * @see #endFakeDrag()
+     */
+    public boolean beginFakeDrag() {
+        if (mIsBeingDragged) {
+            return false;
+        }
+        mFakeDragging = true;
+        setScrollState(SCROLL_STATE_DRAGGING);
+        mInitialMotionX = mLastMotionX = 0;
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        } else {
+            mVelocityTracker.clear();
+        }
+        final long time = SystemClock.uptimeMillis();
+        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);
+        mVelocityTracker.addMovement(ev);
+        ev.recycle();
+        mFakeDragBeginTime = time;
+        return true;
+    }
+
+    /**
+     * End a fake drag of the pager.
+     *
+     * @see #beginFakeDrag()
+     * @see #fakeDragBy(float)
+     */
+    public void endFakeDrag() {
+        if (!mFakeDragging) {
+            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
+        }
+
+        final VelocityTracker velocityTracker = mVelocityTracker;
+        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+        int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
+        mPopulatePending = true;
+        final int width = getClientWidth();
+        final int scrollX = getScrollX();
+        final ItemInfo ii = infoForCurrentScrollPosition();
+        final int currentPage = ii.position;
+        final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
+        final int totalDelta = (int) (mLastMotionX - mInitialMotionX);
+        int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
+                totalDelta);
+        setCurrentItemInternal(nextPage, true, true, initialVelocity);
+        endDrag();
+
+        mFakeDragging = false;
+    }
+
+    /**
+     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.
+     *
+     * @param xOffset Offset in pixels to drag by.
+     * @see #beginFakeDrag()
+     * @see #endFakeDrag()
+     */
+    public void fakeDragBy(float xOffset) {
+        if (!mFakeDragging) {
+            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
+        }
+
+        mLastMotionX += xOffset;
+
+        float oldScrollX = getScrollX();
+        float scrollX = oldScrollX - xOffset;
+        final int width = getClientWidth();
+
+        float leftBound = width * mFirstOffset;
+        float rightBound = width * mLastOffset;
+
+        final ItemInfo firstItem = mItems.get(0);
+        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+        if (firstItem.position != 0) {
+            leftBound = firstItem.offset * width;
+        }
+        if (lastItem.position != mAdapter.getCount() - 1) {
+            rightBound = lastItem.offset * width;
+        }
+
+        if (scrollX < leftBound) {
+            scrollX = leftBound;
+        } else if (scrollX > rightBound) {
+            scrollX = rightBound;
+        }
+        // Don't lose the rounded component
+        mLastMotionX += scrollX - (int) scrollX;
+        scrollTo((int) scrollX, getScrollY());
+        pageScrolled((int) scrollX);
+
+        // Synthesize an event for the VelocityTracker.
+        final long time = SystemClock.uptimeMillis();
+        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,
+                mLastMotionX, 0, 0);
+        mVelocityTracker.addMovement(ev);
+        ev.recycle();
+    }
+
+    /**
+     * Returns true if a fake drag is in progress.
+     *
+     * @return true if currently in a fake drag, false otherwise.
+     *
+     * @see #beginFakeDrag()
+     * @see #fakeDragBy(float)
+     * @see #endFakeDrag()
+     */
+    public boolean isFakeDragging() {
+        return mFakeDragging;
+    }
+
+    private void onSecondaryPointerUp(MotionEvent ev) {
+        final int pointerIndex = ev.getActionIndex();
+        final int pointerId = ev.getPointerId(pointerIndex);
+        if (pointerId == mActivePointerId) {
+            // This was our active pointer going up. Choose a new
+            // active pointer and adjust accordingly.
+            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+            mLastMotionX = ev.getX(newPointerIndex);
+            mActivePointerId = ev.getPointerId(newPointerIndex);
+            if (mVelocityTracker != null) {
+                mVelocityTracker.clear();
+            }
+        }
+    }
+
+    private void endDrag() {
+        mIsBeingDragged = false;
+        mIsUnableToDrag = false;
+
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    private void setScrollingCacheEnabled(boolean enabled) {
+        if (mScrollingCacheEnabled != enabled) {
+            mScrollingCacheEnabled = enabled;
+            if (USE_CACHE) {
+                final int size = getChildCount();
+                for (int i = 0; i < size; ++i) {
+                    final View child = getChildAt(i);
+                    if (child.getVisibility() != GONE) {
+                        child.setDrawingCacheEnabled(enabled);
+                    }
+                }
+            }
+        }
+    }
+
+    public boolean canScrollHorizontally(int direction) {
+        if (mAdapter == null) {
+            return false;
+        }
+
+        final int width = getClientWidth();
+        final int scrollX = getScrollX();
+        if (direction < 0) {
+            return (scrollX > (int) (width * mFirstOffset));
+        } else if (direction > 0) {
+            return (scrollX < (int) (width * mLastOffset));
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Tests scrollability within child views of v given a delta of dx.
+     *
+     * @param v View to test for horizontal scrollability
+     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
+     *               or just its children (false).
+     * @param dx Delta scrolled in pixels
+     * @param x X coordinate of the active touch point
+     * @param y Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            // Count backwards - let topmost views consume scroll distance first.
+            for (int i = count - 1; i >= 0; i--) {
+                // TODO: Add versioned support here for transformed views.
+                // This will not work for transformed views in Honeycomb+
+                final View child = group.getChildAt(i);
+                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
+                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
+                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
+                                y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+
+        return checkV && v.canScrollHorizontally(-dx);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        // Let the focused view and/or our descendants get the key first
+        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
+    }
+
+    /**
+     * You can call this function yourself to have the scroll view perform
+     * scrolling from a key event, just as if the event had been dispatched to
+     * it by the view hierarchy.
+     *
+     * @param event The key event to execute.
+     * @return Return true if the event was handled, else false.
+     */
+    public boolean executeKeyEvent(KeyEvent event) {
+        boolean handled = false;
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (event.getKeyCode()) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    handled = arrowScroll(FOCUS_LEFT);
+                    break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    handled = arrowScroll(FOCUS_RIGHT);
+                    break;
+                case KeyEvent.KEYCODE_TAB:
+                    if (event.hasNoModifiers()) {
+                        handled = arrowScroll(FOCUS_FORWARD);
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                        handled = arrowScroll(FOCUS_BACKWARD);
+                    }
+                    break;
+            }
+        }
+        return handled;
+    }
+
+    public boolean arrowScroll(int direction) {
+        View currentFocused = findFocus();
+        if (currentFocused == this) {
+            currentFocused = null;
+        } else if (currentFocused != null) {
+            boolean isChild = false;
+            for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+                    parent = parent.getParent()) {
+                if (parent == this) {
+                    isChild = true;
+                    break;
+                }
+            }
+            if (!isChild) {
+                // This would cause the focus search down below to fail in fun ways.
+                final StringBuilder sb = new StringBuilder();
+                sb.append(currentFocused.getClass().getSimpleName());
+                for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+                        parent = parent.getParent()) {
+                    sb.append(" => ").append(parent.getClass().getSimpleName());
+                }
+                Log.e(TAG, "arrowScroll tried to find focus based on non-child " +
+                        "current focused view " + sb.toString());
+                currentFocused = null;
+            }
+        }
+
+        boolean handled = false;
+
+        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,
+                direction);
+        if (nextFocused != null && nextFocused != currentFocused) {
+            if (direction == View.FOCUS_LEFT) {
+                // If there is nothing to the left, or this is causing us to
+                // jump to the right, then what we really want to do is page left.
+                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
+                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
+                if (currentFocused != null && nextLeft >= currLeft) {
+                    handled = pageLeft();
+                } else {
+                    handled = nextFocused.requestFocus();
+                }
+            } else if (direction == View.FOCUS_RIGHT) {
+                // If there is nothing to the right, or this is causing us to
+                // jump to the left, then what we really want to do is page right.
+                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
+                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
+                if (currentFocused != null && nextLeft <= currLeft) {
+                    handled = pageRight();
+                } else {
+                    handled = nextFocused.requestFocus();
+                }
+            }
+        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
+            // Trying to move left and nothing there; try to page.
+            handled = pageLeft();
+        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
+            // Trying to move right and nothing there; try to page.
+            handled = pageRight();
+        }
+        if (handled) {
+            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
+        }
+        return handled;
+    }
+
+    private Rect getChildRectInPagerCoordinates(Rect outRect, View child) {
+        if (outRect == null) {
+            outRect = new Rect();
+        }
+        if (child == null) {
+            outRect.set(0, 0, 0, 0);
+            return outRect;
+        }
+        outRect.left = child.getLeft();
+        outRect.right = child.getRight();
+        outRect.top = child.getTop();
+        outRect.bottom = child.getBottom();
+
+        ViewParent parent = child.getParent();
+        while (parent instanceof ViewGroup && parent != this) {
+            final ViewGroup group = (ViewGroup) parent;
+            outRect.left += group.getLeft();
+            outRect.right += group.getRight();
+            outRect.top += group.getTop();
+            outRect.bottom += group.getBottom();
+
+            parent = group.getParent();
+        }
+        return outRect;
+    }
+
+    boolean pageLeft() {
+        if (mCurItem > 0) {
+            setCurrentItem(mCurItem-1, true);
+            return true;
+        }
+        return false;
+    }
+
+    boolean pageRight() {
+        if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) {
+            setCurrentItem(mCurItem+1, true);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * We only want the current page that is being shown to be focusable.
+     */
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        final int focusableCount = views.size();
+
+        final int descendantFocusability = getDescendantFocusability();
+
+        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
+            for (int i = 0; i < getChildCount(); i++) {
+                final View child = getChildAt(i);
+                if (child.getVisibility() == VISIBLE) {
+                    ItemInfo ii = infoForChild(child);
+                    if (ii != null && ii.position == mCurItem) {
+                        child.addFocusables(views, direction, focusableMode);
+                    }
+                }
+            }
+        }
+
+        // we add ourselves (if focusable) in all cases except for when we are
+        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
+        // to avoid the focus search finding layouts when a more precise search
+        // among the focusable children would be more interesting.
+        if (
+            descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
+                // No focusable descendants
+                (focusableCount == views.size())) {
+            // Note that we can't call the superclass here, because it will
+            // add all views in.  So we need to do the same thing View does.
+            if (!isFocusable()) {
+                return;
+            }
+            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&
+                    isInTouchMode() && !isFocusableInTouchMode()) {
+                return;
+            }
+            if (views != null) {
+                views.add(this);
+            }
+        }
+    }
+
+    /**
+     * We only want the current page that is being shown to be touchable.
+     */
+    @Override
+    public void addTouchables(ArrayList<View> views) {
+        // Note that we don't call super.addTouchables(), which means that
+        // we don't call View.addTouchables().  This is okay because a ViewPager
+        // is itself not touchable.
+        for (int i = 0; i < getChildCount(); i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem) {
+                    child.addTouchables(views);
+                }
+            }
+        }
+    }
+
+    /**
+     * We only want the current page that is being shown to be focusable.
+     */
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction,
+            Rect previouslyFocusedRect) {
+        int index;
+        int increment;
+        int end;
+        int count = getChildCount();
+        if ((direction & FOCUS_FORWARD) != 0) {
+            index = 0;
+            increment = 1;
+            end = count;
+        } else {
+            index = count - 1;
+            increment = -1;
+            end = -1;
+        }
+        for (int i = index; i != end; i += increment) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem) {
+                    if (child.requestFocus(direction, previouslyFocusedRect)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        // Dispatch scroll events from this ViewPager.
+        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+            return super.dispatchPopulateAccessibilityEvent(event);
+        }
+
+        // Dispatch all other accessibility events from the current page.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                final ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem &&
+                        child.dispatchPopulateAccessibilityEvent(event)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return generateDefaultLayoutParams();
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams && super.checkLayoutParams(p);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    class MyAccessibilityDelegate extends AccessibilityDelegate {
+
+        @Override
+        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+            super.onInitializeAccessibilityEvent(host, event);
+            event.setClassName(ViewPager.class.getName());
+            final AccessibilityRecord record = AccessibilityRecord.obtain();
+            record.setScrollable(canScroll());
+            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED
+                    && mAdapter != null) {
+                record.setItemCount(mAdapter.getCount());
+                record.setFromIndex(mCurItem);
+                record.setToIndex(mCurItem);
+            }
+        }
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(host, info);
+            info.setClassName(ViewPager.class.getName());
+            info.setScrollable(canScroll());
+            if (canScrollHorizontally(1)) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            }
+            if (canScrollHorizontally(-1)) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            }
+        }
+
+        @Override
+        public boolean performAccessibilityAction(View host, int action, Bundle args) {
+            if (super.performAccessibilityAction(host, action, args)) {
+                return true;
+            }
+            switch (action) {
+                case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                    if (canScrollHorizontally(1)) {
+                        setCurrentItem(mCurItem + 1);
+                        return true;
+                    }
+                } return false;
+                case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                    if (canScrollHorizontally(-1)) {
+                        setCurrentItem(mCurItem - 1);
+                        return true;
+                    }
+                } return false;
+            }
+            return false;
+        }
+
+        private boolean canScroll() {
+            return (mAdapter != null) && (mAdapter.getCount() > 1);
+        }
+    }
+
+    private class PagerObserver extends DataSetObserver {
+        @Override
+        public void onChanged() {
+            dataSetChanged();
+        }
+        @Override
+        public void onInvalidated() {
+            dataSetChanged();
+        }
+    }
+
+    /**
+     * Layout parameters that should be supplied for views added to a
+     * ViewPager.
+     */
+    public static class LayoutParams extends ViewGroup.LayoutParams {
+        /**
+         * true if this view is a decoration on the pager itself and not
+         * a view supplied by the adapter.
+         */
+        public boolean isDecor;
+
+        /**
+         * Gravity setting for use on decor views only:
+         * Where to position the view page within the overall ViewPager
+         * container; constants are defined in {@link android.view.Gravity}.
+         */
+        public int gravity;
+
+        /**
+         * Width as a 0-1 multiplier of the measured pager width
+         */
+        float widthFactor = 0.f;
+
+        /**
+         * true if this view was added during layout and needs to be measured
+         * before being positioned.
+         */
+        boolean needsMeasure;
+
+        /**
+         * Adapter position this view is for if !isDecor
+         */
+        int position;
+
+        /**
+         * Current child index within the ViewPager that this view occupies
+         */
+        int childIndex;
+
+        public LayoutParams() {
+            super(FILL_PARENT, FILL_PARENT);
+        }
+
+        public LayoutParams(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
+            gravity = a.getInteger(0, Gravity.TOP);
+            a.recycle();
+        }
+    }
+
+    static class ViewPositionComparator implements Comparator<View> {
+        @Override
+        public int compare(View lhs, View rhs) {
+            final LayoutParams llp = (LayoutParams) lhs.getLayoutParams();
+            final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams();
+            if (llp.isDecor != rlp.isDecor) {
+                return llp.isDecor ? 1 : -1;
+            }
+            return llp.position - rlp.position;
+        }
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 28f1a3a..30a7e68 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -18,6 +18,8 @@
 
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
+LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
+
 LOCAL_SRC_FILES:= \
     AndroidRuntime.cpp \
     com_android_internal_content_NativeLibraryHelper.cpp \
@@ -41,25 +43,25 @@
     android_database_SQLiteDebug.cpp \
     android_emoji_EmojiFactory.cpp \
     android_view_DisplayEventReceiver.cpp \
-    android_view_Surface.cpp \
-    android_view_SurfaceControl.cpp \
-    android_view_SurfaceSession.cpp \
-    android_view_TextureView.cpp \
+    android_view_DisplayListCanvas.cpp \
+    android_view_GraphicBuffer.cpp \
+    android_view_HardwareLayer.cpp \
     android_view_InputChannel.cpp \
     android_view_InputDevice.cpp \
     android_view_InputEventReceiver.cpp \
     android_view_InputEventSender.cpp \
     android_view_InputQueue.cpp \
-    android_view_KeyEvent.cpp \
     android_view_KeyCharacterMap.cpp \
-    android_view_GraphicBuffer.cpp \
-    android_view_GLES20Canvas.cpp \
-    android_view_HardwareLayer.cpp \
-    android_view_ThreadedRenderer.cpp \
+    android_view_KeyEvent.cpp \
     android_view_MotionEvent.cpp \
     android_view_PointerIcon.cpp \
     android_view_RenderNode.cpp \
     android_view_RenderNodeAnimator.cpp \
+    android_view_Surface.cpp \
+    android_view_SurfaceControl.cpp \
+    android_view_SurfaceSession.cpp \
+    android_view_TextureView.cpp \
+    android_view_ThreadedRenderer.cpp \
     android_view_VelocityTracker.cpp \
     android_text_AndroidCharacter.cpp \
     android_text_AndroidBidi.cpp \
@@ -147,7 +149,7 @@
     android_hardware_location_ActivityRecognitionHardware.cpp \
     android_util_FileObserver.cpp \
     android/opengl/poly_clip.cpp.arm \
-    android/opengl/util.cpp.arm \
+    android/opengl/util.cpp \
     android_server_FingerprintManager.cpp \
     android_server_NetworkManagementSocketTagger.cpp \
     android_server_Watchdog.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 008f877..ad52e3f 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -127,16 +127,16 @@
 extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
+extern int register_android_view_DisplayListCanvas(JNIEnv* env);
+extern int register_android_view_GraphicBuffer(JNIEnv* env);
+extern int register_android_view_HardwareLayer(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
-extern int register_android_view_GraphicBuffer(JNIEnv* env);
-extern int register_android_view_GLES20Canvas(JNIEnv* env);
-extern int register_android_view_HardwareLayer(JNIEnv* env);
-extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
 extern int register_android_database_SQLiteConnection(JNIEnv* env);
@@ -546,6 +546,9 @@
     char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
     char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
     char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
+    char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX];
+    char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
+    char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -642,6 +645,13 @@
                        heaptargetutilizationOptsBuf,
                        "-XX:HeapTargetUtilization=");
 
+    /*
+     * JIT related options.
+     */
+    parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
+    parseRuntimeOption("dalvik.vm.jitcodecachesize", jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
+    parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
+
     property_get("ro.config.low_ram", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
       addOption("-XX:LowMemoryMode");
@@ -1169,7 +1179,7 @@
     REG_JNI(register_android_view_RenderNode),
     REG_JNI(register_android_view_RenderNodeAnimator),
     REG_JNI(register_android_view_GraphicBuffer),
-    REG_JNI(register_android_view_GLES20Canvas),
+    REG_JNI(register_android_view_DisplayListCanvas),
     REG_JNI(register_android_view_HardwareLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 672008d..6a50b52 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -41,7 +41,6 @@
 jfieldID gOptions_mCancelID;
 jfieldID gOptions_bitmapFieldID;
 
-jfieldID gBitmap_nativeBitmapFieldID;
 jfieldID gBitmap_ninePatchInsetsFieldID;
 
 jclass gInsetStruct_class;
@@ -262,7 +261,7 @@
     SkBitmap* outputBitmap = NULL;
     unsigned int existingBufferSize = 0;
     if (javaBitmap != NULL) {
-        outputBitmap = (SkBitmap*) env->GetLongField(javaBitmap, gBitmap_nativeBitmapFieldID);
+        outputBitmap = GraphicsJNI::getSkBitmap(env, javaBitmap);
         if (outputBitmap->isImmutable()) {
             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
             javaBitmap = NULL;
@@ -601,7 +600,6 @@
     gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z");
 
     jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap");
-    gBitmap_nativeBitmapFieldID = GetFieldIDOrDie(env, bitmap_class, "mNativeBitmap", "J");
     gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets",
             "Landroid/graphics/NinePatch$InsetStruct;");
 
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 90a7f69..04afe3e 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -213,7 +213,7 @@
 
     if (tileBitmap != NULL) {
         // Re-use bitmap.
-        bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap);
+        bitmap = GraphicsJNI::getSkBitmap(env, tileBitmap);
     }
     if (bitmap == NULL) {
         bitmap = new SkBitmap;
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 026cbee..d03bcf0 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -21,7 +21,7 @@
 
 #include "SkColorFilter.h"
 #include "SkColorMatrixFilter.h"
-#include "SkPorterDuff.h"
+#include "SkXfermode.h"
 
 #include <Caches.h>
 
@@ -36,10 +36,9 @@
         if (filter) SkSafeUnref(filter);
     }
 
-    static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
-            jint modeHandle) {
-        SkPorterDuff::Mode mode = (SkPorterDuff::Mode) modeHandle;
-        return reinterpret_cast<jlong>(SkColorFilter::CreateModeFilter(srcColor, SkPorterDuff::ToXfermodeMode(mode)));
+    static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) {
+        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+        return reinterpret_cast<jlong>(SkColorFilter::CreateModeFilter(srcColor, mode));
     }
 
     static jlong CreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index dde1393..0747969 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -154,7 +154,7 @@
 static jfieldID gPointF_yFieldID;
 
 static jclass   gBitmap_class;
-static jfieldID gBitmap_nativeInstanceID;
+static jfieldID gBitmap_skBitmapPtr;
 static jmethodID gBitmap_constructorMethodID;
 static jmethodID gBitmap_reinitMethodID;
 static jmethodID gBitmap_getAllocationByteCountMethodID;
@@ -338,11 +338,11 @@
     return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
 }
 
-SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
+SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) {
     SkASSERT(env);
     SkASSERT(bitmap);
     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
-    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativeInstanceID);
+    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_skBitmapPtr);
     SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkASSERT(b);
     return b;
@@ -676,7 +676,7 @@
     gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
 
     gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
-    gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "J");
+    gBitmap_skBitmapPtr = getFieldIDCheck(env, gBitmap_class, "mSkBitmapPtr", "J");
     gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(J[BIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
     gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
     gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index a202c38..422d3f1 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -48,7 +48,7 @@
     static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
 
     static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
-    static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
+    static SkBitmap* getSkBitmap(JNIEnv*, jobject bitmap);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     // Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
index 73b1691..d65864d 100644
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -24,7 +24,7 @@
 #include "GraphicsJNI.h"
 #include "core_jni_helpers.h"
 
-#include "SkPorterDuff.h"
+#include "SkXfermode.h"
 
 namespace android {
 
@@ -32,8 +32,28 @@
 public:
 
     static jlong CreateXfermode(JNIEnv* env, jobject, jint modeHandle) {
-        SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
-        return reinterpret_cast<jlong>(SkPorterDuff::CreateXfermode(mode));
+        // validate that the Java enum values match our expectations
+        SK_COMPILE_ASSERT(0  == SkXfermode::kClear_Mode,    xfermode_mismatch);
+        SK_COMPILE_ASSERT(1  == SkXfermode::kSrc_Mode,      xfermode_mismatch);
+        SK_COMPILE_ASSERT(2  == SkXfermode::kDst_Mode,      xfermode_mismatch);
+        SK_COMPILE_ASSERT(3  == SkXfermode::kSrcOver_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(4  == SkXfermode::kDstOver_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(5  == SkXfermode::kSrcIn_Mode,    xfermode_mismatch);
+        SK_COMPILE_ASSERT(6  == SkXfermode::kDstIn_Mode,    xfermode_mismatch);
+        SK_COMPILE_ASSERT(7  == SkXfermode::kSrcOut_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(8  == SkXfermode::kDstOut_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(9  == SkXfermode::kSrcATop_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(10 == SkXfermode::kDstATop_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(11 == SkXfermode::kXor_Mode,      xfermode_mismatch);
+        SK_COMPILE_ASSERT(16 == SkXfermode::kDarken_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(17 == SkXfermode::kLighten_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(13 == SkXfermode::kModulate_Mode, xfermode_mismatch);
+        SK_COMPILE_ASSERT(14 == SkXfermode::kScreen_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(12 == SkXfermode::kPlus_Mode,     xfermode_mismatch);
+        SK_COMPILE_ASSERT(15 == SkXfermode::kOverlay_Mode,  xfermode_mismatch);
+        
+        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+        return reinterpret_cast<jlong>(SkXfermode::Create(mode));
     }
  
 };
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 3f47a72..6591d29 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -3,7 +3,6 @@
 
 #include "SkShader.h"
 #include "SkGradientShader.h"
-#include "SkPorterDuff.h"
 #include "SkComposeShader.h"
 #include "SkTemplates.h"
 #include "SkXfermode.h"
@@ -227,14 +226,13 @@
 }
 
 static jlong ComposeShader_create2(JNIEnv* env, jobject o,
-        jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle)
+        jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
 {
     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
-    SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
-    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
-    SkXfermode* mode = (SkXfermode*) au.get();
-    SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
+    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
+    SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
+    SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
     return reinterpret_cast<jlong>(shader);
 }
 
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 461507f..5c2d0d0 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -16,6 +16,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
+#include "GraphicsJNI.h"
 
 #include <math.h>
 #include <stdio.h>
@@ -149,10 +150,6 @@
     return result;
 }
 
-static void doThrowIAE(JNIEnv* env, const char* msg) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", msg);
-}
-
 template<class JArray, class T>
 class ArrayHelper {
 public:
@@ -548,14 +545,6 @@
 
 // ---------------------------------------------------------------------------
 
-static jfieldID nativeBitmapID = 0;
-
-void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
-{
-    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
-    nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
-}
-
 extern void setGLDebugLevel(int level);
 void setTracingLevel(JNIEnv *env, jclass clazz, jint level)
 {
@@ -629,16 +618,14 @@
 static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     return getInternalFormat(nativeBitmap->colorType());
 }
 
 static jint util_getType(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     return getType(nativeBitmap->colorType());
 }
 
@@ -646,8 +633,7 @@
         jint target, jint level, jint internalformat,
         jobject jbitmap, jint type, jint border)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
     SkColorType colorType = bitmap.colorType();
     if (internalformat < 0) {
@@ -694,8 +680,7 @@
         jint target, jint level, jint xoffset, jint yoffset,
         jobject jbitmap, jint format, jint type)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
     SkColorType colorType = bitmap.colorType();
     if (format < 0) {
@@ -1014,7 +999,6 @@
 };
 
 static JNINativeMethod gUtilsMethods[] = {
-    {"nativeClassInit", "()V",                          (void*)nativeUtilsClassInit },
     { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
     { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
     { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 7d5ca8d..c337a9f 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -21,7 +21,6 @@
 #include <Canvas.h>
 #include "SkDrawFilter.h"
 #include "SkGraphics.h"
-#include "SkPorterDuff.h"
 #include "Paint.h"
 #include "TypefaceImpl.h"
 
@@ -186,8 +185,8 @@
 }
 
 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
-     SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
-     get_canvas(canvasHandle)->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
+    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+    get_canvas(canvasHandle)->drawColor(color, mode);
 }
 
 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index db73e69..e5ae147 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -29,6 +29,7 @@
 #include <list>
 #include <algorithm>
 
+
 namespace android {
 
 struct JLineBreaksID {
@@ -40,6 +41,53 @@
 static jclass gLineBreaks_class;
 static JLineBreaksID gLineBreaks_fieldID;
 
+class Builder {
+    public:
+        ~Builder() {
+            utext_close(&mUText);
+            delete mBreakIterator;
+        }
+
+        void setLocale(const icu::Locale& locale) {
+            delete mBreakIterator;
+            UErrorCode status = U_ZERO_ERROR;
+            mBreakIterator = icu::BreakIterator::createLineInstance(locale, status);
+            // TODO: check status
+        }
+
+        void resize(size_t size) {
+            mTextBuf.resize(size);
+        }
+
+        uint16_t* buffer() {
+            return mTextBuf.data();
+        }
+
+        // set text to current contents of buffer
+        void setText() {
+            UErrorCode status = U_ZERO_ERROR;
+            utext_openUChars(&mUText, mTextBuf.data(), mTextBuf.size(), &status);
+            mBreakIterator->setText(&mUText, status);
+        }
+
+        void finish() {
+            if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) {
+                mTextBuf.clear();
+                mTextBuf.shrink_to_fit();
+            }
+        }
+
+        icu::BreakIterator* breakIterator() const {
+            return mBreakIterator;
+        }
+
+    private:
+        const size_t MAX_TEXT_BUF_RETAIN = 32678;
+        icu::BreakIterator* mBreakIterator = nullptr;
+        UText mUText = UTEXT_INITIALIZER;
+        std::vector<uint16_t>mTextBuf;
+};
+
 static const int CHAR_SPACE = 0x20;
 static const int CHAR_TAB = 0x09;
 static const int CHAR_NEWLINE = 0x0a;
@@ -50,7 +98,7 @@
         // specified stops must be a sorted array (allowed to be null)
         TabStops(JNIEnv* env, jintArray stops, jint defaultTabWidth) :
             mStops(env), mTabWidth(defaultTabWidth) {
-                if (stops != NULL) {
+                if (stops != nullptr) {
                     mStops.reset(stops);
                     mNumStops = mStops.size();
                 } else {
@@ -430,37 +478,6 @@
         }
 };
 
-class ScopedBreakIterator {
-    public:
-        ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, const jchar* inputText,
-                            jint length) : mBreakIterator(breakIterator), mChars(inputText) {
-            UErrorCode status = U_ZERO_ERROR;
-            mUText = utext_openUChars(NULL, mChars, length, &status);
-            if (mUText == NULL) {
-                return;
-            }
-
-            mBreakIterator->setText(mUText, status);
-        }
-
-        inline BreakIterator* operator->() {
-            return mBreakIterator;
-        }
-
-        ~ScopedBreakIterator() {
-            utext_close(mUText);
-            delete mBreakIterator;
-        }
-    private:
-        BreakIterator* mBreakIterator;
-        const jchar* mChars;
-        UText* mUText;
-
-        // disable copying and assignment
-        ScopedBreakIterator(const ScopedBreakIterator&);
-        void operator=(const ScopedBreakIterator&);
-};
-
 static jint recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
                         jfloatArray recycleWidths, jbooleanArray recycleFlags,
                         jint recycleLength, const std::vector<jint>& breaks,
@@ -526,7 +543,7 @@
     primitives->push_back(p);
 }
 
-static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName,
+static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
                                jcharArray inputText, jfloatArray widths, jint length,
                                jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
                                jintArray variableTabStops, jint defaultTabStop, jboolean optimize,
@@ -535,29 +552,24 @@
                                jint recycleLength) {
     std::vector<int> breaks;
 
-    ScopedCharArrayRO textScopedArr(env, inputText);
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    b->resize(length);
+    env->GetCharArrayRegion(inputText, 0, length, b->buffer());
+    b->setText();
+
+    // TODO: this array access is pretty inefficient, but we'll replace it anyway
     ScopedFloatArrayRO widthsScopedArr(env, widths);
 
-    ScopedIcuLocale icuLocale(env, javaLocaleName);
-    if (icuLocale.valid()) {
-        UErrorCode status = U_ZERO_ERROR;
-        BreakIterator* it = BreakIterator::createLineInstance(icuLocale.locale(), status);
-        if (!U_SUCCESS(status) || it == NULL) {
-            if (it) {
-                delete it;
-            }
-        } else {
-            ScopedBreakIterator breakIterator(env, it, textScopedArr.get(), length);
-            int loc = breakIterator->first();
-            while ((loc = breakIterator->next()) != BreakIterator::DONE) {
-                breaks.push_back(loc);
-            }
-        }
+    icu::BreakIterator* breakIterator = b->breakIterator();
+    int loc = breakIterator->first();
+    while ((loc = breakIterator->next()) != icu::BreakIterator::DONE) {
+        breaks.push_back(loc);
     }
 
+    // TODO: all these allocations can be moved into the builder
     std::vector<Primitive> primitives;
     TabStops tabStops(env, variableTabStops, defaultTabStop);
-    computePrimitives(textScopedArr.get(), widthsScopedArr.get(), length, breaks, tabStops, &primitives);
+    computePrimitives(b->buffer(), widthsScopedArr.get(), length, breaks, tabStops, &primitives);
 
     LineWidth lineWidth(firstWidth, firstWidthLineLimit, restWidth);
     std::vector<int> computedBreaks;
@@ -571,13 +583,41 @@
         GreedyLineBreaker breaker(primitives, lineWidth);
         breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
     }
+    b->finish();
 
     return recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
             computedBreaks, computedWidths, computedFlags);
 }
 
+static jlong nNewBuilder(JNIEnv*, jclass) {
+    return reinterpret_cast<jlong>(new Builder);
+}
+
+static void nFreeBuilder(JNIEnv*, jclass, jlong nativePtr) {
+    delete reinterpret_cast<Builder*>(nativePtr);
+}
+
+static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    b->finish();
+}
+
+static void nBuilderSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) {
+    ScopedIcuLocale icuLocale(env, javaLocaleName);
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+
+    if (icuLocale.valid()) {
+        b->setLocale(icuLocale.locale());
+    }
+}
+
 static JNINativeMethod gMethods[] = {
-    {"nComputeLineBreaks", "(Ljava/lang/String;[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I", (void*) nComputeLineBreaks}
+    {"nNewBuilder", "()J", (void*) nNewBuilder},
+    {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
+    {"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
+    {"nBuilderSetLocale", "(JLjava/lang/String;)V", (void*) nBuilderSetLocale},
+    {"nComputeLineBreaks", "(J[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
+        (void*) nComputeLineBreaks}
 };
 
 int register_android_text_StaticLayout(JNIEnv* env)
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
similarity index 82%
rename from core/jni/android_view_GLES20Canvas.cpp
rename to core/jni/android_view_DisplayListCanvas.cpp
index 0bee7ae..f2e6c4b 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -50,43 +50,43 @@
 // Setup
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_setViewport(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint width, jint height) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->setViewport(width, height);
 }
 
-static void android_view_GLES20Canvas_setHighContrastText(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_setHighContrastText(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jboolean highContrastText) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->setHighContrastText(highContrastText);
 }
 
-static void android_view_GLES20Canvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jboolean reorderEnable) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->insertReorderBarrier(reorderEnable);
 }
 
-static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_prepare(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->prepare();
 }
 
-static void android_view_GLES20Canvas_prepareDirty(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_prepareDirty(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint left, jint top, jint right, jint bottom) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->prepareDirty(left, top, right, bottom);
 }
 
-static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_finish(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->finish();
 }
 
-static void android_view_GLES20Canvas_setProperty(JNIEnv* env,
+static void android_view_DisplayListCanvas_setProperty(JNIEnv* env,
         jobject clazz, jstring name, jstring value) {
     if (!Caches::hasInstance()) {
         ALOGW("can't set property, no Caches instance");
@@ -108,7 +108,7 @@
 // Functor
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong functorPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
@@ -120,11 +120,11 @@
 // Misc
 // ----------------------------------------------------------------------------
 
-static jint android_view_GLES20Canvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
+static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
     return Caches::getInstance().maxTextureSize;
 }
 
-static jint android_view_GLES20Canvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
+static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
     return Caches::getInstance().maxTextureSize;
 }
 
@@ -132,7 +132,7 @@
 // Drawing
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawPatch(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong bitmapPtr, jlong patchPtr,
         float left, float top, float right, float bottom, jlong paintPtr) {
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
@@ -143,7 +143,7 @@
     renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
 }
 
-static void android_view_GLES20Canvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
         jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
@@ -157,7 +157,7 @@
     renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
 }
 
-static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
@@ -167,7 +167,7 @@
     renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
 }
 
-static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong regionPtr, jlong paintPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
@@ -201,17 +201,17 @@
 // Display lists
 // ----------------------------------------------------------------------------
 
-static jlong android_view_GLES20Canvas_finishRecording(JNIEnv* env,
+static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
         jobject clazz, jlong rendererPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     return reinterpret_cast<jlong>(renderer->finishRecording());
 }
 
-static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
+static jlong android_view_DisplayListCanvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
     return reinterpret_cast<jlong>(new DisplayListRenderer);
 }
 
-static void android_view_GLES20Canvas_drawRenderNode(JNIEnv* env,
+static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
         jobject clazz, jlong rendererPtr, jlong renderNodePtr,
         jint flags) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
@@ -224,7 +224,7 @@
 // Layers
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
@@ -235,7 +235,7 @@
 // Common
 // ----------------------------------------------------------------------------
 
-static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz) {
+static jboolean android_view_DisplayListCanvas_isAvailable(JNIEnv* env, jobject clazz) {
     char prop[PROPERTY_VALUE_MAX];
     if (property_get("ro.kernel.qemu", prop, NULL) == 0) {
         // not in the emulator
@@ -261,36 +261,36 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/view/GLES20Canvas";
+const char* const kClassPathName = "android/view/DisplayListCanvas";
 
 static JNINativeMethod gMethods[] = {
-    { "nIsAvailable",       "()Z",             (void*) android_view_GLES20Canvas_isAvailable },
-    { "nSetViewport",       "(JII)V",          (void*) android_view_GLES20Canvas_setViewport },
-    { "nSetHighContrastText","(JZ)V",          (void*) android_view_GLES20Canvas_setHighContrastText },
-    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_GLES20Canvas_insertReorderBarrier },
-    { "nPrepare",           "(J)V",            (void*) android_view_GLES20Canvas_prepare },
-    { "nPrepareDirty",      "(JIIII)V",        (void*) android_view_GLES20Canvas_prepareDirty },
-    { "nFinish",            "(J)V",            (void*) android_view_GLES20Canvas_finish },
+    { "nIsAvailable",       "()Z",             (void*) android_view_DisplayListCanvas_isAvailable },
+    { "nSetViewport",       "(JII)V",          (void*) android_view_DisplayListCanvas_setViewport },
+    { "nSetHighContrastText","(JZ)V",          (void*) android_view_DisplayListCanvas_setHighContrastText },
+    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_DisplayListCanvas_insertReorderBarrier },
+    { "nPrepare",           "(J)V",            (void*) android_view_DisplayListCanvas_prepare },
+    { "nPrepareDirty",      "(JIIII)V",        (void*) android_view_DisplayListCanvas_prepareDirty },
+    { "nFinish",            "(J)V",            (void*) android_view_DisplayListCanvas_finish },
     { "nSetProperty",       "(Ljava/lang/String;Ljava/lang/String;)V",
-            (void*) android_view_GLES20Canvas_setProperty },
+            (void*) android_view_DisplayListCanvas_setProperty },
 
-    { "nCallDrawGLFunction", "(JJ)V",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
+    { "nCallDrawGLFunction", "(JJ)V",          (void*) android_view_DisplayListCanvas_callDrawGLFunction },
 
-    { "nDrawPatch",         "(JJJFFFFJ)V",     (void*) android_view_GLES20Canvas_drawPatch },
+    { "nDrawPatch",         "(JJJFFFFJ)V",     (void*) android_view_DisplayListCanvas_drawPatch },
 
-    { "nDrawRects",         "(JJJ)V",          (void*) android_view_GLES20Canvas_drawRegionAsRects },
-    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_GLES20Canvas_drawRoundRectProps },
-    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_GLES20Canvas_drawCircleProps },
+    { "nDrawRects",         "(JJJ)V",          (void*) android_view_DisplayListCanvas_drawRegionAsRects },
+    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_DisplayListCanvas_drawRoundRectProps },
+    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_DisplayListCanvas_drawCircleProps },
 
-    { "nFinishRecording",   "(J)J",            (void*) android_view_GLES20Canvas_finishRecording },
-    { "nDrawRenderNode",    "(JJI)V",          (void*) android_view_GLES20Canvas_drawRenderNode },
+    { "nFinishRecording",   "(J)J",            (void*) android_view_DisplayListCanvas_finishRecording },
+    { "nDrawRenderNode",    "(JJI)V",          (void*) android_view_DisplayListCanvas_drawRenderNode },
 
-    { "nCreateDisplayListRenderer", "()J",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+    { "nCreateDisplayListRenderer", "()J",     (void*) android_view_DisplayListCanvas_createDisplayListRenderer },
 
-    { "nDrawLayer",               "(JJFF)V",   (void*) android_view_GLES20Canvas_drawLayer },
+    { "nDrawLayer",               "(JJFF)V",   (void*) android_view_DisplayListCanvas_drawLayer },
 
-    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_GLES20Canvas_getMaxTextureWidth },
-    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_GLES20Canvas_getMaxTextureHeight },
+    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
+    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
 };
 
 static JNINativeMethod gActivityThreadMethods[] = {
@@ -298,7 +298,7 @@
                                                (void*) android_app_ActivityThread_dumpGraphics }
 };
 
-int register_android_view_GLES20Canvas(JNIEnv* env) {
+int register_android_view_DisplayListCanvas(JNIEnv* env) {
     jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
     gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
 
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index bbd031e..f6d9a1a 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -80,7 +80,7 @@
 
     jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap);
     if (bitmapObj) {
-        SkBitmap* bitmap = GraphicsJNI::getNativeBitmap(env, bitmapObj);
+        SkBitmap* bitmap = GraphicsJNI::getSkBitmap(env, bitmapObj);
         if (bitmap) {
             outPointerIcon->bitmap = *bitmap; // use a shared pixel ref
         }
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index bfa0534..39064ed 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -130,6 +130,100 @@
     return surfaceObj;
 }
 
+int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f) {
+
+    switch(f) {
+        case PublicFormat::JPEG:
+        case PublicFormat::DEPTH_POINT_CLOUD:
+            return HAL_PIXEL_FORMAT_BLOB;
+        case PublicFormat::DEPTH16:
+            return HAL_PIXEL_FORMAT_Y16;
+        case PublicFormat::RAW_SENSOR:
+            return HAL_PIXEL_FORMAT_RAW16;
+        default:
+            // Most formats map 1:1
+            return static_cast<int>(f);
+    }
+}
+
+android_dataspace android_view_Surface_mapPublicFormatToHalDataspace(
+        PublicFormat f) {
+    switch(f) {
+        case PublicFormat::JPEG:
+            return HAL_DATASPACE_JFIF;
+        case PublicFormat::DEPTH_POINT_CLOUD:
+        case PublicFormat::DEPTH16:
+            return HAL_DATASPACE_DEPTH;
+        case PublicFormat::RAW_SENSOR:
+        case PublicFormat::RAW10:
+            return HAL_DATASPACE_ARBITRARY;
+        case PublicFormat::YUV_420_888:
+        case PublicFormat::NV21:
+        case PublicFormat::YV12:
+            return HAL_DATASPACE_JFIF;
+        default:
+            // Most formats map to UNKNOWN
+            return HAL_DATASPACE_UNKNOWN;
+    }
+}
+
+PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat(
+        int format, android_dataspace dataSpace) {
+    switch(format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+        case HAL_PIXEL_FORMAT_Y8:
+        case HAL_PIXEL_FORMAT_RAW10:
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+        case HAL_PIXEL_FORMAT_YV12:
+            // Enums overlap in both name and value
+            return static_cast<PublicFormat>(format);
+        case HAL_PIXEL_FORMAT_RAW16:
+            // Name differs, though value is the same
+            return PublicFormat::RAW_SENSOR;
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+            // Name differs, though the value is the same
+            return PublicFormat::NV16;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            // Name differs, though the value is the same
+            return PublicFormat::NV21;
+        case HAL_PIXEL_FORMAT_YCbCr_422_I:
+            // Name differs, though the value is the same
+            return PublicFormat::YUY2;
+        case HAL_PIXEL_FORMAT_Y16:
+            // Dataspace-dependent
+            switch (dataSpace) {
+                case HAL_DATASPACE_DEPTH:
+                    return PublicFormat::DEPTH16;
+                default:
+                    // Assume non-depth Y16 is just Y16.
+                    return PublicFormat::Y16;
+            }
+            break;
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Dataspace-dependent
+            switch (dataSpace) {
+                case HAL_DATASPACE_DEPTH:
+                    return PublicFormat::DEPTH_POINT_CLOUD;
+                case HAL_DATASPACE_JFIF:
+                    return PublicFormat::JPEG;
+                default:
+                    // Assume otherwise-marked blobs are also JPEG
+                    return PublicFormat::JPEG;
+            }
+            break;
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+        case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+            // Not defined in public API
+            return PublicFormat::UNKNOWN;
+
+        default:
+            return PublicFormat::UNKNOWN;
+    }
+}
 // ----------------------------------------------------------------------------
 
 static inline bool isSurfaceValid(const sp<Surface>& sur) {
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 6c21bab..7080e2a 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -30,6 +30,7 @@
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 
+#include <GraphicsJNI.h>
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
 
@@ -46,7 +47,6 @@
 static jfieldID gSurface_EGLSurfaceFieldID;
 static jfieldID gSurface_NativePixelRefFieldID;
 static jfieldID gConfig_EGLConfigFieldID;
-static jfieldID gBitmap_NativeBitmapFieldID;
 
 static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
     if (!o) return EGL_NO_DISPLAY;
@@ -85,9 +85,6 @@
     jclass surface_class = _env->FindClass("com/google/android/gles_jni/EGLSurfaceImpl");
     gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "J");
     gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "J");
-
-    jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
-    gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "J");
 }
 
 static const jint gNull_attrib_base[] = {EGL_NONE};
@@ -280,9 +277,7 @@
     EGLConfig  cnf = getConfig(_env, config);
     jint* base = 0;
 
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(native_pixmap,
-                    gBitmap_NativeBitmapFieldID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(_env, native_pixmap);
     SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0;
     if (ref == NULL) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b550558..ed4776b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2892,6 +2892,14 @@
         android:description="@string/permdesc_bindNotificationListenerService"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link
+         android.service.chooser.ChooserTargetService}, to ensure that
+         only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
+        android:label="@string/permlab_bindChooserTargetService"
+        android:description="@string/permdesc_bindChooserTargetService"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Must be required by a {@link
          android.service.notification.ConditionProviderService},
          to ensure that only the system can bind to it.
@@ -3025,6 +3033,19 @@
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
+        <activity android:name="com.android.internal.app.DumpHeapActivity"
+                android:theme="@style/Theme.Translucent.NoTitleBar"
+                android:label="@string/dump_heap_title"
+                android:finishOnCloseSystemDialogs="true"
+                android:noHistory="true"
+                android:excludeFromRecents="true"
+                android:process=":ui">
+        </activity>
+        <provider android:name="com.android.server.am.DumpHeapProvider"
+                android:authorities="com.android.server.heapdump"
+                android:grantUriPermissions="true"
+                android:multiprocess="false"
+                android:singleUser="true" />
 
         <activity android:name="android.accounts.ChooseAccountActivity"
                 android:excludeFromRecents="true"
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
index 9cdc25b..1550b44 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
index 276d480..b309dfd 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
index 95c0168..b36a413 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
index 569332a..afd0bd2 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
index a01ac10..58f8c43 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
index d3602d9..42a893d 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
index 75085ce..d0f274a 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
index e2eb5be..f1f637a 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
new file mode 100644
index 0000000..643168f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
new file mode 100644
index 0000000..e8f3aad
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4d93a83..5a12efb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind aan \'n kennisgewingluisteraardiens"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Laat die houer toe om aan die top-koppelvlak van \'n kennisgewingluisteraardiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind aan \'n kieserteikendiens"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Laat die houer toe om aan die top-koppelvlak van \'n kieserteikendiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"verbind met \'n toestandverskafferdiens"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Laat die houer toe om met die topvlak-koppelvlak van \'n toestandverskafferdiens te verbind. Behoort nooit vir normale programme nodig te wees nie."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind aan \'n mediaroetediens"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Moenie die nuwe program begin nie."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Begin <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop die ou program sonder om te stoor."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Kies \'n handeling vir teks"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Luiervolume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Probeer weer oor 1 sekonde</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Probeer later weer"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swiep van bo af na onder om volskerm te verlaat."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Bekyk tans volskerm"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Swiep van bo na onder as jy wil uitgaan."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Het dit"</string>
     <string name="done_label" msgid="2093726099505892398">"Klaar"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ure se sirkelglyer"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minute se sirkelglyer"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Om hierdie skerm te ontspeld, raak en hou tegelyk Terug en Oorsig."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Om hierdie skerm te ontspeld, raak en hou Oorsig."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skerm is vasgespeld. Jou organisasie laat nie toe dat dit ontspeld word nie."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skerm vasgespeld"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skerm ontspeld"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vra PIN voordat jy ontspeld"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 05818bc..1741851 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ከመራጭ ዒላማ አገልግሎት ጋር ይሰሩ"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ያዢው የመራጩን ዒላማ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጽ ጋር እንዲያስር ይፈቅዳል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ከአንድ የሁኔታ አቅራቢ አገልግሎት ጋር ይሰሩ"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ያዢው የአንድ የሁኔታ አቅራቢ አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ከአንድ ማህደረመረጃ ማዞር አገልግሎት ጋር ያስተሳስራል"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"አዲሱን መተግበሪያ አትጀምር።"</string>
     <string name="new_app_action" msgid="5472756926945440706">"ጀምር <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"የድሮውን ትግበራ ሳታስቀምጥ አቁም።"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ለፅሁፍ ድርጊት ምረጥ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"የስልክ ጥሪ ድምፅ"</string>
     <string name="volume_music" msgid="5421651157138628171">" ማህደረ መረጃ  ክፍልፍል"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other">በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ቆይተው እንደገና ይሞክሩ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ከሙሉ ገጽ ማያ ለመውጣት ጣትዎን ከላይ ወደታች ያንሸራትቱ።"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"ሙሉ ገጽ በማሳየት ላይ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ለመውጣት፣ ከላይ ወደታች ጠረግ ያድርጉ።"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ገባኝ"</string>
     <string name="done_label" msgid="2093726099505892398">"ተከናውኗል"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"የሰዓታት ክብ ተንሸራታች"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"የደቂቃዎች ክብ ተንሸራታች"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ይህን ማያ ገጽ ለመንቀል ተመለስን እና አጠቃላይ እይታን በተመሳሳይ ይንኳቸውና ይያዟቸው።"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ይህን ማያ ገጽ ለመንቀል አጠቃላይ እይታን ይንኩትና ይያዙት።"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ማያ ገጽ ተሰክቷል። መንቀል በድርጅትዎ አይፈቀድም።"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ማያ ገጽ ተነቅሏል"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ከመንቀል በፊት ፒን ጠይቅ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 8021de0..1d1fe54 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -800,6 +800,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"الربط بخدمة اختيار الهدف"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة اختيار الهدف. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"الربط بخدمة موفر الحالة"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة موفر الحالة. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"الربط بخدمة توجيه الوسائط"</string>
@@ -1283,6 +1285,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"عدم بدء التطبيق الجديد."</string>
     <string name="new_app_action" msgid="5472756926945440706">"بدء <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"إيقاف التطبيق القديم بدون الحفظ."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"اختيار إجراء للنص"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"مستوى صوت الرنين"</string>
     <string name="volume_music" msgid="5421651157138628171">"مستوى صوت الوسائط"</string>
@@ -1812,7 +1822,9 @@
       <item quantity="one">حاول مرة أخرى خلال ثانية واحدة</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"أعد المحاولة لاحقًا"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"مرر بسرعة من أعلى لأسفل للخروج من وضع ملء الشاشة."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"جارٍ العرض بملء الشاشة"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"للخروج، مرر بسرعة من أعلى إلى أسفل."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"حسنًا"</string>
     <string name="done_label" msgid="2093726099505892398">"تم"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"شريط التمرير الدائري للساعات"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"شريط التمرير الدائري للدقائق"</string>
@@ -1827,7 +1839,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> المخصص للعمل"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"رجوع\" و\"نظرة عامة\" في آن واحد مع الاستمرار."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"نظرة عامة\" مع الاستمرار."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"الشاشة مثبتة. لا تسمح منظمتك بإلغاء التثبيت."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"تم تثبيت الشاشة"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"تم إلغاء تثبيت الشاشة"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"المطالبة برقم التعريف الشخصي قبل إزالة التثبيت"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 125611f..0ca9f51 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"свързване с целева услуга в инструмент за избор"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на целева услуга в инструмент за избор. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"свързване с услуга за предоставяне на условия"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за предоставяне на условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"свързване с услуга за маршрутизиране на мултимедия"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Новото приложение да не се стартира."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Стартиране на <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Спиране на старото приложение без запазване."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Избиране на действие за текст"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Сила на звука при звънене"</string>
     <string name="volume_music" msgid="5421651157138628171">"Сила на звука"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Опитайте отново след 1 секунда</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Опитайте отново по-късно"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"За изход от цял екран прекарайте пръст отгоре надолу."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Изглед на цял екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"За изход прекарайте пръст надолу от горната част."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Разбрах"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Кръгов плъзгач за часовете"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Кръгов плъзгач за минутите"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> за работа"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"За да освободите екрана, докоснете и задръжте едновременно бутона за връщане назад и този за общ преглед."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"За да освободите този екран, докоснете и задръжте бутона „Общ преглед“."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екранът е фиксиран. Освобождаването не е разрешено от организацията ви."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екранът е фиксиран"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екранът е освободен"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитване за ПИН код преди освобождаване"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index f9ebf28..8a60320 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"অ্যাপ্লিকেশানটিকে অন্যান্য অ্যাপ্লিকেশান যেগুলি পোস্ট করে সেগুলি সমেত, বিজ্ঞপ্তিগুলি পুনরুদ্ধার করতে, পরীক্ষা করতে এবং সাফ করার অনুমতি দেয়৷"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"একটি বিজ্ঞপ্তি শ্রোতা পরিষেবাতে সংলগ্ন করে"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ধারককে, একটি বিজ্ঞপ্তি শ্রোতা পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"একটি লক্ষ চয়নকারী পরিষেবাতে আবদ্ধ করুন"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ধারককে, একটি লক্ষ্য চয়নকারী পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"একটি শর্ত প্রদানকারীর পরিষেবা বাঁধাই করে"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ধারককে, একটি শর্ত প্রদানকারী পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"একটি মিডিয়া রুট পরিষেবায় জুড়ুন"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"নতুন অ্যাপ্লিকেশান চালু করবেন না৷"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> শুরু করুন"</string>
     <string name="new_app_description" msgid="1932143598371537340">"সংরক্ষণ না করেই পুরোনো অ্যাপ্লিকেশানটি বন্ধ করুন৷"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"পাঠ্যের জন্য একটি কাজ বেছে নিন"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"রিং ভলিউম"</string>
     <string name="volume_music" msgid="5421651157138628171">"মিডিয়ার ভলিউম"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"পরে আবার চেষ্টা করুন"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"পূর্ণস্ক্রীণ থেকে প্রস্থান করতে উপর থেকে নীচের দিকে সোয়াইপ করুন৷"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"পূর্ণ স্ক্রীণে দেখা হচ্ছে"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"প্রস্থান করতে উপর থেকে নীচের দিকে সোয়াইপ করুন"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"বুঝেছি"</string>
     <string name="done_label" msgid="2093726099505892398">"সম্পন্ন হয়েছে"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"বৃত্তাকার ঘন্টা নির্বাচকের স্লাইডার"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"বৃত্তাকার মিনিট নির্বাচকের স্লাইডার"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"কর্মক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"এই স্ক্রীনটিকে আনপিন করতে, \'ফিরুন\' এবং \'এক নজরে\' একসাথে স্পর্শ করুন এবং ধরে রাখুন৷"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"এই স্ক্রীনটিকে আনপিন করতে, \'এক নজরে\' স্পর্শ করুন এবং ধরে রাখুন৷"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"স্ক্রীন পিন করা আছে। আপনার প্রতিষ্ঠান এটিকে পিনমুক্ত করার অনুমতি দেয়নি।"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"স্ক্রীন পিন করা হয়েছে"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"পিন না করা স্ক্রীন"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"আনপিন করার আগে PIN চান"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 68768d4..8884cae 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei oient de notificacions"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei oient de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular-se a un servei de destí de selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet que el propietari la pugui vincular a la interfície principal d\'un servei de destí de selector. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enllaçar amb el servei de proveïdor de condicions"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet enllaçar amb la interfície de nivell superior d\'un servei de proveïdor de condicions. No ha de ser mai necessari per a aplicacions normals."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular-se amb un servei de rutes multimèdia"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"No iniciïs l\'aplicació nova."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Inicia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Atura l\'aplicació antiga sense desar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Tria una acció per al text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volum del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volum de multimèdia"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Torna-ho a provar d\'aquí a 1 segon</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Torna-ho a provar més tard"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Fes lliscar el dit cap avall per sortir de la pantalla completa."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualització en pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Per sortir, fes lliscar el dit cap avall des de la part superior."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"D\'acord"</string>
     <string name="done_label" msgid="2093726099505892398">"Fet"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control circular de les hores"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control circular dels minuts"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Per anul·lar la fixació d\'aquesta pantalla, mantén premudes les opcions Enrere i Visió general alhora."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Per anul·lar la fixació d\'aquesta pantalla, mantén premuda l\'opció Visió general."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"S\'ha fixat la pantalla. La teva organització no permet anul·lar-ne la fixació."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Fixació de la pantalla anul·lada"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demana el codi PIN abans d\'anul·lar la fixació"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 253f35c..1a023578 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -798,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"navázání na službu pro poslouchání oznámení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteli navázat se na nejvyšší úroveň služby pro poslouchání oznámení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"navázat se na cílovou službu nástroje pro výběr"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umožňuje držiteli navázat se na rozhraní nejvyšší úrovně cílové služby nástroje pro výběr. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"navázání na službu poskytovatele podmínky"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby poskytovatele podmínky. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"navázání na službu směrování médií"</string>
@@ -1273,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nespouštět novou aplikaci."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Spustit aplikaci <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zastavit starou aplikaci bez uložení."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Vyberte akci pro text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitost vyzvánění"</string>
     <string name="volume_music" msgid="5421651157138628171">"Hlasitost médií"</string>
@@ -1794,7 +1804,9 @@
       <item quantity="one">Zkuste to znovu za 1 sekundu</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Zkuste to znovu později"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Režim celé obrazovky ukončíte přejetím dolů."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Zobrazení celé obrazovky"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Režim ukončíte přejetím prstem shora dolů."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Rozumím"</string>
     <string name="done_label" msgid="2093726099505892398">"Hotovo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kruhový posuvník hodin"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posuvník minut"</string>
@@ -1809,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Pracovní <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Chcete-li tuto obrazovku uvolnit, klepněte současně na možnosti Zpět a Přehled a podržte je."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Chcete-li tuto obrazovku uvolnit, klepněte na možnost Přehled a podržte ji."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Obrazovka je připnuta. Vaše organizace uvolnění zakázala."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka připnuta"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka uvolněna"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Před uvolněním požádat o kód PIN"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 59c276f..07a588a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -786,7 +786,7 @@
     <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Tillader, at appen kan interagere med telefonitjenester for at foretage/modtage opkald."</string>
     <string name="permlab_control_incall_experience" msgid="9061024437607777619">"leverer brugeroplevelsen under opkald"</string>
     <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Tillader, at appen leverer brugeroplevelsen under opkald."</string>
-    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"læse oversigt over netværksbrug"</string>
+    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"læse historisk netværksbrug"</string>
     <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Tillader, at appen kan læse historisk netværksbrug for specifikke netværk og apps."</string>
     <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"administrer netværkspolitik"</string>
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, f.eks. dem, der er sendt af andre apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"knytte sig til en tjeneste til valg af mål"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Tillader, at appen kan knytte sig til det øverste grænsefladeniveau for en tjeneste til valg af mål. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"oprette binding til en tjeneste til formidling af betingelser"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til formidling af betingelser. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"opret binding til en medierutetjeneste"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Åbn ikke den nye app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop den gamle app uden at gemme."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Vælg en handling for teksten"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Lydstyrke for opkald"</string>
     <string name="volume_music" msgid="5421651157138628171">"Lydstyrke for medier"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other">Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Prøv igen senere"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Stryg ned fra toppen for at afslutte fuld skærm"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visning i fuld skærm"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Stryg ned fra toppen for at afslutte."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK, det er forstået"</string>
     <string name="done_label" msgid="2093726099505892398">"Udfør"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Cirkulær timevælger"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Cirkulær minutvælger"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Tilbage og Oversigt på samme tid og holde fingeren nede."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Oversigt og holde fingeren nede."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skærmen er fastgjort. Frigørelse er ikke tilladt af din organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skærmen blev frigjort"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3af1706..72eff6f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Displaysperre deaktivieren"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ermöglicht der App, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. Das Telefon deaktiviert die Tastensperre beispielsweise, wenn ein Anruf eingeht, und aktiviert sie wieder, nachdem das Gespräch beendet wurde."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Fingerabdruckhardware verwalten"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Erlaubt der App, Methoden zum Hinzufügen und Löschen zu verwendender Fingerabdruckvorlagen aufzurufen"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Fingerabdruckhardware verwenden"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Erlaubt der App, Fingerabdruckhardware zur Authentifizierung zu verwenden"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Synchronisierung aktivieren oder deaktivieren"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Inhaber, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"An einen Zielauswahldienst binden"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Zielauswahldienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"An einen Bedingungsproviderdienst binden"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Bedingungsproviderdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"An Mediarouting-Dienst binden"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Neue App nicht starten"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Alte App beenden, ohne zu speichern"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Aktion für Text auswählen"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="one">In 1 Sek. wiederholen</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Später erneut versuchen"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Zum Schließen des Vollbilds von oben nach unten wischen"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Vollbildmodus wird aktiviert"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Zum Beenden von oben nach unten wischen"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Fertig"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kreisförmiger Schieberegler für Stunden"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kreisförmiger Schieberegler für Minuten"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie gleichzeitig \"Zurück\" und \"Übersicht\"."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie \"Übersicht\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Der Bildschirm ist fixiert. Sie sind nicht berechtigt, diese Einstellung zu beenden."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Bildschirm fixiert"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Bildschirm gelöst"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0779d06..caa3408 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"δέσμευση σε υπηρεσία επιλογής στόχευσης"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας επιλογής στόχευσης. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"σύνδεση σε μια υπηρεσία παρόχου συνθηκών"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου ενός παρόχου συνθηκών. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"σύνδεση σε μια υπηρεσία δρομολόγησης μέσων"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Μην εκκινήσετε τη νέα εφαρμογή."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Εκκίνηση της εφαρμογής <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Διακοπή της παλιάς εφαρμογής χωρίς αποθήκευση."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Επιλέξτε μια ενέργεια για το κείμενο"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ένταση ήχου ειδοποίησης"</string>
     <string name="volume_music" msgid="5421651157138628171">"Ένταση ήχου πολυμέσων"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Δοκιμάστε ξανά σε 1 δευτερόλεπτο</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Δοκιμάστε ξανά αργότερα"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Σάρωση προς τα κάτω για έξοδο από πλήρη οθόνη"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Προβολή σε πλήρη οθόνη"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Για έξοδο, σύρετε προς τα κάτω από το επάνω μέρος."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Το κατάλαβα"</string>
     <string name="done_label" msgid="2093726099505892398">"Τέλος"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Κυκλικό ρυθμιστικό ωρών"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Κυκλικό ρυθμιστικό λεπτών"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Εργασία <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, πατήστε παρατεταμένα \"Επιστροφή\" και \"Επισκόπηση\" ταυτόχρονα."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, αγγίξτε παρατεταμένα \"Επισκόπηση\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Η οθόνη καρφιστώθηκε. Το ξεκαρφίτσωμα δεν επιτρέπεται από τον οργανισμό σας."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Η οθόνη καρφιτσώθηκε"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Η οθόνη ξεκαρφιτσώθηκε"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b8bd7eb..e75df385 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind to a chooser target service"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind to a media route service"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Choose an action for text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringer volume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Media volume"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Try again in 1 second</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Viewing full screen"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"To exit, swipe down from the top."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Got it"</string>
     <string name="done_label" msgid="2093726099505892398">"Done"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"To unpin this screen, touch and hold Overview."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Screen is pinned. Unpinning isn\'t allowed by your organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Screen unpinned"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b8bd7eb..e75df385 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind to a chooser target service"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind to a media route service"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Choose an action for text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringer volume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Media volume"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Try again in 1 second</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Viewing full screen"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"To exit, swipe down from the top."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Got it"</string>
     <string name="done_label" msgid="2093726099505892398">"Done"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"To unpin this screen, touch and hold Overview."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Screen is pinned. Unpinning isn\'t allowed by your organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Screen unpinned"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index e3f3476..84718dd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivar el bloqueo de pantalla"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que la aplicación desactive el bloqueo del teclado y cualquier protección con contraseña asociada. Por ejemplo, el dispositivo puede desactivar el bloqueo del teclado cuando recibe una llamada telefónica y volver a activarlo cuando finaliza la llamada."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Administrar el hardware de huellas digitales"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que la aplicación emplee métodos para agregar y eliminar plantillas de huellas digitales para su uso."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utilizar hardware de huellas digitales"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Este permiso permite que la aplicación consulte la configuración de sincronización de una cuenta. Esto permite, por ejemplo, determinar si la aplicación Personas está sincronizada con una cuenta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Vincular a un servicio de agente de escucha de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de agente de escucha de notificaciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincularse a un servicio de destino selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de destino. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular con un servicio de proveedor de condiciones"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite vincular con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a un servicio de enrutamiento de contenido multimedia"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Inicio <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Interrumpe la aplicación anterior sin guardar los cambios."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Seleccionar una acción para el texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volumen de los medios"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="one">Vuelve a intentarlo en 1 segundo.</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Vuelve a intentar más tarde."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Desliza el dedo hacia abajo para salir de la pantalla completa."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualización en pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para salir, desliza el dedo hacia abajo desde la parte superior."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendido"</string>
     <string name="done_label" msgid="2093726099505892398">"Listo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control deslizante circular de horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para dejar de fijar esta pantalla, mantén presionados los botones para volver y Recientes al mismo tiempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para dejar de fijar esta pantalla, mantén presionado el botón Recientes."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"La pantalla está fija. La organización no permite dejar de fijar la pantalla."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fija"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla no fija"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index b5d5397..df148a0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"inhabilitar el bloqueo de pantalla"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que la aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Por ejemplo, el teléfono puede inhabilitar el bloqueo del teclado cuando se recibe una llamada telefónica y volver a habilitarlo cuando finaliza la llamada."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"administrar hardware de huellas digitales"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que la aplicación invoque métodos para añadir y eliminar plantillas de huellas digitales y utilizarlas."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizar hardware de huellas digitales"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que la aplicación consulte la configuración de sincronización de una cuenta. La aplicación puede utilizar este permiso, por ejemplo, para determinar si la aplicación Contactos está sincronizada con una cuenta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"enlazar con un servicio de destino selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite que el titular enlace con la interfaz de nivel superior de un servicio de destino selector. Las aplicaciones normales no deberían necesitar nunca este permiso."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enlazar con un servicio de proveedor de condiciones"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite enlazar con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"enlazar a un servicio de rutas multimedia"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Detener la aplicación anterior sin guardar"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Selecciona una acción para el texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volumen multimedia"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="one">Vuelve a intentarlo en 1 segundo</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Volver a intentar más tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Desliza el dedo hacia abajo para salir de la pantalla completa"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Mostrando pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para salir, desliza el dedo hacia abajo desde la parte superior de la pantalla."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendido"</string>
     <string name="done_label" msgid="2093726099505892398">"Listo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control deslizante circular de horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para desactivar esta pantalla, mantén pulsados los botones de retroceso y Visión general al mismo tiempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para desactivar esta pantalla, mantén pulsado Visión general."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Se ha activado la pantalla. Tu organización no puede desactivarla."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fijada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"La pantalla ya no está fija"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para desactivar"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index c7a07b8..a428496 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"seo märguannete kuulamisteenusega"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Võimaldab omanikul siduda märguannete kuulamisteenuse ülemise taseme kasutajaliidese. Seda ei tohiks tavarakenduste puhul kunagi vaja olla."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"valija sihtteenusega sidumine"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Võimaldab omanikul siduda valija sihtteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"seo tingimuse pakkuja teenusega"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lubab omanikul siduda tingimuse pakkuja teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"meediumi marsruutimise teenusega sidumine"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ärge käivitage uut rakendust."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Käivitage rakendus <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Peatage vana rakendus salvestamata."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Valige teksti jaoks toiming"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Helina helitugevus"</string>
     <string name="volume_music" msgid="5421651157138628171">"Meediumi helitugevus"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Proovige uuesti 1 sekundi pärast</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Proovige hiljem uuesti"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Täisekraanilt väljumiseks pühkige ülevalt alla."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Kuvamine täisekraanil"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Väljumiseks pühkige ülevalt alla."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Selge"</string>
     <string name="done_label" msgid="2093726099505892398">"Valmis"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ringikujuline tunniliugur"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Ringikujuline minutiliugur"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ekraanikuva vabastamiseks puudutage pikalt samal ajal nuppe Tagasi ja Ülevaade."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ekraanikuva vabastamiseks puudutage pikalt nuppu Ülevaade."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekraan on kinnitatud. Teie organisatsioon ei luba vabastamist."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekraan on kinnitatud"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekraan on vabastatud"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Enne vabastamist küsi PIN-koodi"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 90b9a62..953a5fa 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Jakinarazpenak berreskuratu, aztertu eta garbitzeko aukera ematen die aplikazioei, beste aplikazioek argitaratutako jakinarazpenak barne."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Lotu jakinarazpenak hautemateko zerbitzu batera"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Jakinarazpenak hautemateko zerbitzu baten goi-mailako interfazera lotzeko aukera ematen dio titularrari. Aplikazio normalek ez dute baimen hau behar."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Lotu hautatzailearen zerbitzu jakin batera"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Zerbitzu jakin baten goi-mailako interfazera lotzea baimentzen die titularrei. Aplikazio normalek ez dute baimen hau behar."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Lotu baldintza-hornitzaileen zerbitzuei"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Baldintza-hornitzaileen zerbitzuen goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"lotetsi multimedia-irteerako zerbitzu bati"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ez abiarazi aplikazio berria."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Hasi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Gelditu aplikazio zaharra ezer gorde gabe."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Aukeratu testurako ekintza"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Tonu-jotzailearen bolumena"</string>
     <string name="volume_music" msgid="5421651157138628171">"Multimedia-edukiaren bolumena"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Saiatu berriro segundo bat igarotakoan</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Saiatu berriro geroago"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Pantaila osotik irteteko, pasatu hatza goitik behera."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Pantaila osoan ikusten"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Irteteko, pasatu hatza goitik behera."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ados"</string>
     <string name="done_label" msgid="2093726099505892398">"Eginda"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ordua aukeratzeko ikuspegi zirkularra"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minutuak aukeratzeko ikuspegi zirkularra"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Aingura kentzeko, eduki ukituta Atzera eta Ikuspegi orokorra botoiak aldi berean."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Aingura kentzeko, eduki ukituta Ikuspegi orokorra botoia."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Pantaila ainguratu da. Erakundeak ez du aingura kentzea onartzen."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Aingura kendu zaio pantailari"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 91cbfcd..7419f5b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامه‌های عادی لازم شود."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"اتصال به یک سرویس هدف‌یابی انتخابگر"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"به دارنده اجازه می‌دهد به رابط سطح بالای یک سرویس هدف‌یابی انتخابگر متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"مقید بودن به سرویس ارائه‌دهنده وضعیت"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"به دارنده امکان می‌دهد تا به واسط سطح بالای سرویس ارائه‌دهنده وضعیت مقید باشد. برای برنامه‌های عادی هرگز نباید لازم باشد."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"اتصال به یک سرویس مسیر رسانه‌ای"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"برنامه جدید شروع نشود."</string>
     <string name="new_app_action" msgid="5472756926945440706">"شروع <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"برنامه قدیمی را بدون ذخیره متوقف کنید."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"انتخاب یک عملکرد برای نوشتار"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"میزان صدای زنگ"</string>
     <string name="volume_music" msgid="5421651157138628171">"میزان صدای رسانه"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ثانیه دیگر دوباره امتحان کنید</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"بعداً دوباره امتحان کنید"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"برای خروج از حالت تمام صفحه، انگشت خود را به تندی از بالای صفحه به پایین بکشید."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"مشاهده در حالت تمام صفحه"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"متوجه شدم"</string>
     <string name="done_label" msgid="2093726099505892398">"انجام شد"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"لغزنده دایره‌ای ساعت"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"لغزنده دایره‌ای دقیقه"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> محل کار"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"برای برداشتن پین این صفحه، هم‌زمان «بازگشت» و «نمای کلی» را لمس کنید و نگه دارید."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"برای برداشتن پین این صفحه، «نمای کلی» را لمس کنید و نگه دارید."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"صفحه پین شده است. سازمان شما برداشتن پین را غیرمجاز کرده است."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"صفحه پین شد"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"پین صفحه برداشته شد"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"درخواست کد پین قبل از برداشتن پین"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 36246cc..9eed4a1 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Antaa sovelluksen sitoutua ilmoituskuuntelijan ylimmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"luo sidos valitsimen kohdepalveluun"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Antaa sovelluksen luoda sidoksen valitsimen kohdepalvelun ylemmän tason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ehtojen toimituspalveluun sitominen"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Antaa sovelluksen luoda sidoksen ehtojen toimituspalvelun ylätason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"median reitityspalveluun sitoutuminen"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Älä käynnistä uutta sovellusta."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Käynnistä <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Pysäytä vanha sovellus tallentamatta."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Valitse tekstille toiminto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Soittoäänen voimakkuus"</string>
     <string name="volume_music" msgid="5421651157138628171">"Median äänenvoimakkuus"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Yritä uudelleen 1 sekunnin kuluttua</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Yritä myöhemmin uudelleen"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Poistu koko näytön tilasta pyyhkäisemällä alas."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Koko ruudun tilassa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Sulje palkki pyyhkäisemällä alas ruudun ylälaidasta."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Selvä"</string>
     <string name="done_label" msgid="2093726099505892398">"Valmis"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Tuntien ympyränmuotoinen liukusäädin"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minuuttien ympyränmuotoinen liukusäädin"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (työ)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Poista näytön kiinnitys painamalla Edellinen- ja Viimeisimmät-kohtaa samanaikaisesti pitkään."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Poista näytön kiinnitys painamalla Viimeisimmät-kohtaa pitkään."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Näyttö on kiinnitetty. Irrottaminen ei ole sallittu organisaatiossasi."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Näyttö kiinnitetty"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Näyttö irrotettu"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN-koodi ennen irrotusta"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 39a19b6..8002744 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -572,7 +572,7 @@
     <string name="permdesc_mediaContentControl" msgid="1637478200272062">"Permet à l\'application de contrôler la lecture des contenus multimédias et d\'accéder aux données associées (titre, auteur...)."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifier vos paramètres audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"enregistrer fichier audio"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"enregistrer des fichiers audio"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Permet à l\'application d\'enregistrer des contenus audio à l\'aide du microphone. Cette autorisation lui donne la possibilité d\'enregistrer du contenu audio à tout moment sans votre consentement."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"Communication avec la carte SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permet à l\'application d\'envoyer des commandes à la carte SIM. Cette fonctionnalité est très dangereuse."</string>
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet à l\'application de communiquer avec des bornes, des cartes et des lecteurs compatibles avec la technologie NFC (communication en champ proche)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"désactiver le verrouillage de l\'écran"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité par mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gérer le matériel d\'empreinte digitale"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permet à l\'application de faire appel à des méthodes d\'ajout et de suppression de modèles d\'empreinte digitale que vous pouvez utiliser."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"utiliser le matériel d\'empreinte digitale"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permet à l\'application d\'utiliser du matériel d\'empreinte digitale pour l\'authentification"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer ou désactiver la synchronisation"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"se lier à un service cible de sélecteur"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet au propriétaire de se lier à l\'interface de haut niveau d\'un service cible de sélecteur. Ne devrait jamais être nécessaire pour les applications normales."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"s\'associer à un service d\'itinéraires multimédias"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Sélectionner une action pour le texte"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="other">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> secondes</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Réessayez plus tard"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Balayez vers le bas pour quitter le mode plein écran"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Affichage plein écran"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Pour quitter, balayez vers le bas à partir du haut."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Terminé"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Curseur circulaire des heures"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage de cet écran, appuyez de manière prolongée sur Retour et Aperçu simultanément."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pour annuler l\'épinglage, appuyez de manière prolongée sur Aperçu."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"L\'écran est épinglé. Votre organisation n\'autorise pas l\'annulation d\'épinglage."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le NIP avant d\'annuler l\'épinglage"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6e57d58..c1fe962 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -620,7 +620,7 @@
     <string name="permdesc_hardware_test" msgid="6597964191208016605">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
     <string name="permlab_fm" msgid="8749504526866832">"accéder aux radios FM"</string>
     <string name="permdesc_fm" msgid="4145699441237962818">"Permet à l\'application d\'accéder aux radios FM afin d\'écouter des programmes."</string>
-    <string name="permlab_callPhone" msgid="3925836347681847954">"Appeler directement les numéros de téléphone"</string>
+    <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"Appel direct de tout numéro de téléphone"</string>
     <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Permet à l\'application d\'appeler n\'importe quel numéro de téléphone, y compris les numéros d\'urgence, sans votre intervention. Des applications malveillantes peuvent passer des appels inutiles et interdits aux services d\'urgence."</string>
@@ -694,7 +694,7 @@
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permet à l\'application de créer des sockets réseau et d\'utiliser des protocoles réseau personnalisés. Le navigateur et d\'autres applications permettent d\'envoyer des données sur Internet. Cette autorisation n\'est donc pas nécessaire pour envoyer des données sur Internet."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"changer/intercepter les paramètres et le trafic du réseau"</string>
     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Permet à l\'application de modifier les paramètres réseau, ainsi que d\'intercepter et de surveiller tout le trafic réseau ayant pour but de modifier le proxy et le port d\'un APN, par exemple. Des applications malveillantes peuvent exploiter cette fonctionnalité pour surveiller, rediriger ou modifier les paquets réseau à votre insu."</string>
-    <string name="permlab_changeNetworkState" msgid="958884291454327309">"Modification de la connectivité du réseau"</string>
+    <string name="permlab_changeNetworkState" msgid="958884291454327309">"modifier la connectivité réseau"</string>
     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permet à l\'application de modifier l\'état de la connectivité du réseau."</string>
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"changer la connectivité du partage de connexion"</string>
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permet à l\'application de modifier l\'état de la connectivité du partage de connexion."</string>
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet à l\'application de communiquer avec des tags, des cartes et des lecteurs compatibles avec la technologie NFC (communication en champ proche)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"désactiver le verrouillage de l\'écran"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité via mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Gérer le matériel d\'empreintes digitales"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Autoriser l\'application à invoquer des méthodes pour ajouter et supprimer des modèles d\'empreintes digitales"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utiliser le matériel d\'empreintes digitales"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Autoriser l\'application à utiliser le matériel d\'empreintes digitales pour l\'authentification"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer/désactiver la synchronisation"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"S\'associer à un service de cible d\'un sélecteur"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet à l\'application autorisée de s\'associer à l\'interface de niveau supérieur du service de cible d\'un sélecteur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"s\'associer à un service d\'itinéraires médias"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Sélectionner une action pour le texte"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="other">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> secondes</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Veuillez réessayer ultérieurement."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Faites glisser le doigt vers le bas pour quitter le mode plein écran."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Affichage en plein écran"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Pour quitter, balayez l\'écran du haut vers le bas."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"OK"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Curseur circulaire des heures"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage, appuyez de manière prolongée et simultanée sur \"Retour\" et \"Aperçu\"."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pour annuler l\'épinglage, appuyez de manière prolongée sur \"Aperçu\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"L\'écran est épinglé. L\'annulation de l\'épinglage n\'est pas autorisée par votre organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé."</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé."</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le code PIN avant d\'annuler l\'épinglage"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 03f1d87..e593f88 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite á aplicación recuperar, examinar e borrar notificacións, incluídas as publicadas por outras aplicacións."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a un servizo de axente de escoita de notificacións"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite ao propietario vincularse á interface de nivel superior dun servizo axente de escoita de notificacións.  Non debería ser nunca necesario para as aplicacións normais."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a un servizo de segmento de seleccionador"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao propietario vincularse á interface de nivel superior dun servizo de segmento de seleccionador. Non debería ser nunca necesario para as aplicacións normais."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a un servizo de provedor de condicións"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite ao propietario vincularse á interface de nivel superior dun servizo provedor de condicións. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a un servizo de ruta de medios"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Non inicies a aplicación nova."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Deter a aplicación antiga sen gardar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Seleccionar unha acción para o texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume do timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume dos elementos multimedia"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Téntao de novo dentro nun segundo</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Téntao de novo máis tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Pasa o dedo cara abaixo desde a parte superior para saír da pantalla completa."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Vendo pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para saír, pasa o dedo cara abaixo desde arriba."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"De acordo"</string>
     <string name="done_label" msgid="2093726099505892398">"Feito"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control de desprazamento circular das horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control de desprazamento circular dos minutos"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar a pantalla, mantén premido Atrás e Visión xeral ao mesmo tempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para soltar a pantalla, mantén premido Visión xeral."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A pantalla está fixada. A túa organización non permite desactivar a pantalla."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla desactivada"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar un PIN antes de soltar a pantalla"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1505fa9..f063560 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -738,10 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"ऐप्स  को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्‍क्रीन लॉक अक्षम करें"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
-    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"फ़िंगरप्रिंट हार्डवेयर को प्रबंधित करें"</string>
-    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"फ़िंगरप्रिंट टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string>
-    <string name="permlab_useFingerprint" msgid="3150478619915124905">"फ़िंगरप्रिंट हार्डवेयर का उपयोग करें"</string>
-    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए फ़िंगरप्रिंट हार्डवेयर का उपयोग करने देती है"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"अंगुली की छाप के लिए हार्डवेयर को प्रबंधित करें"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"अंगुली की छाप वाले टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"अंगुली की छाप के लिए हार्डवेयर का उपयोग करें"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए अंगुली की छाप हार्डवेयर का उपयोग करने देती है"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"समन्वयन सेटिंग पढ़ें"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ऐप्स  को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह निर्धारित किया जा सकता है कि लोग ऐप्स  किसी खाते के साथ समन्‍वयित है या नहीं."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"समन्‍वयन बंद या चालू टॉगल करें"</string>
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप्स  को नोटिफिकेशन को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य ऐप्स  के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"नोटिफिकेशन श्रवणकर्ता सेवा से जुड़ें"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को नोटिफिकेशन श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स  के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"किसी चयनकर्ता लक्ष्य सेवा से आबद्ध हों"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"धारक को किसी चयनकर्ता लक्ष्य सेवा के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्‍स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"किसी स्थिति प्रदाता सेवा से आबद्ध हों"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"धारक को किसी स्थिति प्रदाता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मीडिया रूट सेवा से आबद्ध हों"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"नया ऐप्स प्रारंभ न करें."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करें"</string>
     <string name="new_app_description" msgid="1932143598371537340">"पुराने ऐप्स को बिना सहेजे बंद करें."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"लेख के लिए किसी क्रिया को चुनें"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्‍यूम"</string>
     <string name="volume_music" msgid="5421651157138628171">"मीडिया वॉल्‍यूम"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"बाद में फिर से प्रयास करें"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्ण स्क्रीन से बाहर आने के लिए ऊपर से नीचे स्वाइप करें."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन में देखें"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"बाहर निकलने के लिए, ऊपर से नीचे स्वा‍इप करें."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"समझ लिया"</string>
     <string name="done_label" msgid="2093726099505892398">"पूर्ण"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"घंटो का चक्राकार स्लाइडर"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"मिनटों का चक्राकार स्लाइडर"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्यस्थल का <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"इस स्क्रीन को अनपिन करने के लिए, एक ही समय में वापस जाएं और अवलोकन को स्पर्श करके रखें."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"इस स्क्रीन को अनपिन करने के लिए, अवलोकन को स्पर्श करके रखें."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्‍क्रीन पिन की गई है. आपके संगठन के द्वारा अनपिन करने की अनुमति नहीं है."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्‍क्रीन पिन की गई"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्‍क्रीन अनपिन की गई"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करने से पहले पिन के लिए पूछें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index d5a4a0d..59893da2 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -797,6 +797,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vezanje uz uslugu slušatelja obavijesti"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge slušatelja obavijesti. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"povezivanje s uslugom biranja cilja"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Omogućuje nositelju povezivanje sa sučeljem najviše razine usluge biranja cilja. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezivanje s uslugom davatelja uvjeta"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine usluge davatelja uvjeta. Nije potrebno za normalne aplikacije."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"povezivanje s uslugom za usmjeravanje medija"</string>
@@ -1268,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne pokreći novu aplikaciju."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zaustavi staru aplikaciju bez spremanja."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Izaberite radnju za tekst"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Glasnoća zvona"</string>
     <string name="volume_music" msgid="5421651157138628171">"Glasnoća medija"</string>
@@ -1785,7 +1795,9 @@
       <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Prijeđite prstom s vrha prema dolje za izlaz iz cijelog zaslona."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Gledanje preko cijelog zaslona"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Za izlaz prijeđite prstom prema od vrha prema dolje."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Shvaćam"</string>
     <string name="done_label" msgid="2093726099505892398">"Gotovo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kružni klizač sati"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kružni klizač minuta"</string>
@@ -1800,7 +1812,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Da biste otkvačili ovaj zaslon, istovremeno dodirnite i zadržite Natrag i Pregled."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Da biste otkvačili ovaj zaslon, dodirnite i zadržite Pregled."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Zaslon je pričvršćen. Vaša organizacija ne dopušta otkvačivanje."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pričvršćen"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je otkvačen"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN radi otkvačivanja"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 2960784..12a0fb7 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"csatlakozzon értesítésfigyelő szolgáltatáshoz"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lehetővé teszi a használó számára, hogy csatlakozzon egy értesítésfigyelő szolgáltatás legfelső szintű felületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"csatlakozás célválasztó szolgáltatáshoz"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Lehetővé teszi a használó számára, hogy csatlakozzon egy célválasztó szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"csatlakozás egy feltételbiztosító szolgáltatáshoz"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lehetővé teszi a használó számára, hogy csatlakozzon egy feltételbiztosító szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"csatlakozás egy médiaútvonal-szolgáltatáshoz"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne indítsa el az új alkalmazást."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> indítása"</string>
     <string name="new_app_description" msgid="1932143598371537340">"A régi alkalmazás leállítása mentés nélkül."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Válasszon ki egy műveletet a szöveghez"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Csengetés hangereje"</string>
     <string name="volume_music" msgid="5421651157138628171">"Média hangereje"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Próbálja újra 1 másodperc múlva</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Próbálkozzon később"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"A teljes képernyős nézetből való kilépéshez húzza ujját a képernyő tetejétől lefelé."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Megtekintése teljes képernyőn"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Kilépéshez csúsztassa ujját fentről lefelé."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Értem"</string>
     <string name="done_label" msgid="2093726099505892398">"Kész"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Óra kör alakú csúszkája"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Perc kör alakú csúszkája"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza és az Áttekintés lehetőséget egyszerre."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"A képernyő rögzítésének feloldásához tartsa lenyomva az Áttekintés lehetőséget."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A képernyő rögzítve van. Szervezete nem engedélyezi a rögzítés feloldását."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Képernyő rögzítve"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Képernyő rögzítése feloldva"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN kód kérése a rögzítés feloldásához"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 3fe2833..29510b3 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Թույլ է տալիս հավելվածին առբերել, ուսումնասիրել և մաքրել ծանուցումներն, այդ թվում նաև այլ հավելվածների կողմից գրառվածները:"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"միանալ ծանուցումների ունկնդրիչ ծառայությանը"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Թույլ է տալիս սեփականատիրոջը միանալ ծանուցումները ունկնդրող ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"միանալ ընտրողի թիրախային ծառայությանը"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Թույլ է տալիս միանալ ընտրողի թիրախային ծառայության վերին մակարդակի միջերեսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"կապվել պայմանների մատակարարի ծառայությանը"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Թույլ է տալիս սեփականատիրոջը միանալ պայմանների մատակարարների բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"կապվել մեդիա երթուղու ծառայությանը"</string>
@@ -1108,7 +1110,7 @@
     <string name="permlab_readVoicemail" msgid="8415201752589140137">"կարդալ ձայնային փոստը"</string>
     <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Ծրագրին թույլ է տալիս կարդալ ձեր ձայնային փոստը"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"փոփոխել դիտարկչի աշխարհագրական տեղանքի թույլտվությունները"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Թույլ է տալիս հավելվածին փոփոխել զննարկչի աշխարհագրական դիրքի թույլտվությունները: Վնասարար հավելվածները կարող են օգտագործել սա` թույլատրելու ուղարկել տեղադրության վերաբերյալ տեղեկությունները կամայական վեբ կայքերին:"</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Թույլ է տալիս հավելվածին փոփոխել դիտարկչի աշխարհագրական դիրքի թույլտվությունները: Վնասարար հավելվածները կարող են օգտագործել սա` թույլատրելու ուղարկել տեղադրության վերաբերյալ տեղեկությունները կամայական վեբ կայքերին:"</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"հաստատել փաթեթները"</string>
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Թույլ է տալիս հավելվածին հաստատել, որ փաթեթը տեղադրելի է:"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"միանալ փաթեթի ստուգիչին"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Չսկսել նոր հավելված:"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Սկիզբ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Դադարեցնել նախկին ծրագիրն առանց պահպանման:"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Ընտրեք գործողություն տեքստի համար"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Զանգակի ձայնի ուժգնությունը"</string>
     <string name="volume_music" msgid="5421651157138628171">"Մեդիա ձայնի բարձրություն"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other">Կրկին փորձեք <xliff:g id="COUNT">%d</xliff:g> վայրկյանից</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Կրկին փորձեք մի փոքր ուշ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Սահահարվածեք վերից վար՝ ամբողջական էկրանից դուրս գալու համար:"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Լիաէկրան դիտում"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Դուրս գալու համար վերևից սահահարվածեք դեպի ներքև:"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Պարզ է"</string>
     <string name="done_label" msgid="2093726099505892398">"Պատրաստ է"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ժամերի ընտրություն թվատախտակից"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Րոպեների ընտրություն թվատախտակից"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Այս էկրան ապամրացնելու համար միաժամանակ հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Այս էկրանն ապամրացնելու համար հպեք և պահեք Համատեսքի կոճակը:"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Էկրանն ամրացված է: Ապամրացումը չի թույլատրվում ձեր կազմակերպության կողմից:"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Էկրանն ամրացված է"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Էկրանն ապամրացված է"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 96d65ae..502f318 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mengikat layanan pendengar pemberitahuan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Memungkinkan pemegang mengikat antarmuka tingkat teratas dari suatu layanan pendengar pemberitahuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"mengikat ke layanan sasaran pemilik"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan interaksi suara. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"mengikat ke layanan penyedia ketentuan"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan penyedia ketentuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"mengikat ke layanan rute media"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Jangan memulai aplikasi baru."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Mulai <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pilih tindakan untuk teks"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume dering"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume media"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Coba 1 detik lagi</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Coba lagi nanti"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Gesek dari atas ke bawah untuk keluar dari layar penuh."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Melihat layar penuh"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, gesek ke bawah dari atas."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Mengerti"</string>
     <string name="done_label" msgid="2093726099505892398">"Selesai"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Penggeser putar jam"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Penggeser putar menit"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kantor <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk melepas pin layar ini, sentuh lama tombol Kembali dan Ringkasan secara bersamaan."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Untuk melepas pin layar ini, sentuh lama tombol Ringkasan."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Layar disematkan. Pelepasan sematan tidak diizinkan oleh organisasi Anda."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Layar disematkan"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Layar dicopot sematannya"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Meminta PIN sebelum melepas sematan"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 355becb..11b4d98 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Leyfir forriti að sækja, skoða og hreinsa tilkynningar, þ. á m. þær sem önnur forrit birta."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bindast hlustunarþjónustu tilkynninga"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leyfir forriti að bindast efsta viðmótslagi hlustunarþjónustu tilkynninga. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bindast valþjónustu fyrir markmið"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Leyfir handhafa að bindast efsta viðmótslagi valþjónustu fyrir markmið. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bindast þjónustu skilyrðaveitu"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Leyfir handhafa að bindast efsta viðmótslagi skilyrðaveitu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bindast beiningarþjónustu fyrir margmiðlun"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ekki ræsa nýja forritið."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Ræsa <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stöðva gamla forritið án þess að vista."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Veldu aðgerð fyrir texta"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Hljóðstyrkur hringingar"</string>
     <string name="volume_music" msgid="5421651157138628171">"Hljóðstyrkur efnisspilunar"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other">Reyndu aftur eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Reyndu aftur síðar"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Strjúktu niður frá efri brún til að hætta að nota allan skjáinn."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Notar allan skjáinn"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Strjúktu niður frá efri brún til að hætta."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ég skil"</string>
     <string name="done_label" msgid="2093726099505892398">"Lokið"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Valskífa fyrir klukkustundir"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Valskífa fyrir mínútur"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Til að taka lásinn af þessari skjámynd skaltu halda inni Til baka og Yfirliti samtímis."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Til að taka lásinn af þessari skjámynd skaltu halda inni Yfirliti."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skjárinn er festur. Póstskipanin þín leyfir ekki að hann sé losaður."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skjár festur"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skjár opnaður"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9b57ad8..2ab192f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Consente all\'applicazione di comunicare con tag, schede e lettori NFC (Near Field Communication)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"disattivazione blocco schermo"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Consente all\'applicazione di disattivare il blocco tastiera ed eventuali protezioni tramite password associate. Ad esempio, il telefono disattiva il blocco tastiera quando riceve una telefonata in arrivo e lo riattiva al termine della chiamata."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestisci hardware per il riconoscimento delle impronte digitali"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Consente all\'app di richiamare metodi per aggiungere e rimuovere modelli di impronte digitali da utilizzare."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizza hardware per il riconoscimento delle impronte digitali"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Consente all\'app di utilizzare l\'hardware per il riconoscimento delle impronte digitali per eseguire l\'autenticazione"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lettura impostazioni di sincronizz."</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Consente all\'applicazione di leggere le impostazioni di sincronizzazione per un account. Ad esempio, questa autorizzazione può determinare se l\'applicazione Persone è sincronizzata con un account."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"attivazione e disattivazione della sincronizzazione"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincolo a un servizio listener di notifica"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"collegamento al servizio di destinazione di un utente"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Consente al titolare di collegarsi all\'interfaccia di primo livello del servizio di destinazione di un utente. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"collegamento a un servizio provider di condizioni"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio provider di condizioni. Non dovrebbe essere mai necessaria per le normali app."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"associa a servizio di routing multimediale"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Non avviare la nuova applicazione."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Avvia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Interrompi la vecchia applicazione senza salvare."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Scegli un\'azione per il testo"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume suoneria"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume contenuti multimediali"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="one">Riprova tra 1 secondo</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Riprova più tardi"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Scorri dall\'alto verso il basso per uscire dalla modalità schermo intero."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualizzazione a schermo intero"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Per uscire, scorri dall\'alto verso il basso."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Fine"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Dispositivo di scorrimento circolare per le ore"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Dispositivo di scorrimento circolare per i minuti"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Per sbloccare questa schermata, tocca e tieni premute contemporaneamente le opzioni Indietro e Panoramica."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Per sbloccare questa schermata, tocca e tieni premuta l\'opzione Panoramica."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"La schermata è bloccata. La tua organizzazione non ne consente lo sblocco."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Schermata bloccata"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Schermata sbloccata"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Richiedi il PIN prima di sbloccare"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 9f0540f..15c1b35 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -798,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר לאפליקציה לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי אפליקציות אחרות."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילים."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"‏איגוד אל שירות Chooser Target"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"‏מאפשר לבעלים לאגד לממשק ברמה העליונה של שירות Chooser Target. לעולם לא אמור להיות נחוץ עבור אפליקציות רגילות."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"איגוד לשירות ספק תנאי"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות ספק תנאי. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"איגוד לשירות ניתוב מדיה"</string>
@@ -1273,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"אל תפעיל את האפליקציה החדש."</string>
     <string name="new_app_action" msgid="5472756926945440706">"הפעל את <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"עצור את האפליקציה הישן ללא שמירה."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"בחירת פעולה לביצוע עם טקסט"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"עוצמת קול של צלצול"</string>
     <string name="volume_music" msgid="5421651157138628171">"עוצמת קול של מדיה"</string>
@@ -1794,7 +1804,9 @@
       <item quantity="one">נסה שוב בעוד שנייה אחת</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"נסה שוב מאוחר יותר"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"החלק מטה מהחלק העליון כדי לצאת ממסך מלא."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"צפייה במסך מלא"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"כדי לצאת, החלק מלמעלה למטה."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"הבנתי"</string>
     <string name="done_label" msgid="2093726099505892398">"בוצע"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"מחוון שעות מעגלי"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"מחוון דקות מעגלי"</string>
@@ -1809,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"עבודה <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"כדי לבטל את הקפאת המסך הזה, גע בו-זמנית נגיעה ממושכת ב\'הקודם\' ו\'סקירה\'."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"כדי לבטל את הקפאת המסך הזה, גע נגיעה ממושכת ב\'סקירה\'."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"המסך מוצמד. הארגון אוסר לבטל את הצמדתו."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"המסך מוצמד"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"הצמדת המסך בוטלה"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"בקש קוד אימות לפני ביטול הצמדה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 91f72cf..c4849b2 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -528,7 +528,7 @@
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"あなたや友だちのソーシャル更新情報へのアクセスと同期をアプリに許可します。情報の共有は慎重に行ってください。これを許可すると、あなたと友だちがソーシャルネットワークで行ったやり取りを、機密性に関係なくアプリから読み取ることができるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ソーシャルストリームに書く"</string>
     <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"友だちのソーシャル更新情報の表示をアプリに許可します。情報の共有は慎重に行ってください。これによりアプリは、友だちから発信されたかのようなメッセージを作成できるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string>
-    <string name="permlab_readCalendar" msgid="5972727560257612398">"カレンダーの予定と機密情報を読み取る"</string>
+    <string name="permlab_readCalendar" msgid="5972727560257612398">"カレンダーの予定と機密情報の読み取り"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"タブレットに保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string>
     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"テレビに保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string>
     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"携帯端末に保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string>
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"NFCタグ、カード、リーダーとの通信をアプリに許可します。"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"画面ロックの無効化"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"キーロックとキーロックに関連付けられたパスワードのセキュリティを無効にすることをアプリに許可します。たとえば、かかってきた電話を受ける際にキーロックを無効にし、通話が終了したらキーロックを再度有効にする場合などに使用します。"</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"指紋ハードウェアの管理"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"使用する指紋テンプレートの追加や削除を行う方法の呼び出しをアプリに許可します。"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"指紋ハードウェアの使用"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"指紋ハードウェアを認証に使用することをアプリに許可します"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"同期設定の読み取り"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"アカウントの同期設定の読み取りをアプリに許可します。たとえば、連絡帳アプリがアカウントと同期しているかどうかをアプリから特定できるようになります。"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"同期のON/OFFの切り替え"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"選択した対象サービスへのバインド"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"選択した対象サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"コンディションプロバイダサービスへのバインド"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"コンディションプロバイダサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"メディアルートサービスへのバインド"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"新しいアプリを起動しません。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>を起動"</string>
     <string name="new_app_description" msgid="1932143598371537340">"古いアプリを保存せずに停止します。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"アプリケーションを選択"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"着信音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"メディアの音量"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="one">1秒後にもう一度お試しください</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"しばらくしてから再試行"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"全画面表示を終了するには、上から下にスワイプ"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"全画面表示"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"終了するには、上部から下にスワイプします。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"完了"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"円形スライダー(時)"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"円形スライダー(分)"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"仕事の<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"この画面の固定を解除するには[戻る]と[最近]を同時に押し続けます。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"この画面の固定を解除するには[最近]を押し続けます。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"画面が固定されています。会社/組織により解除は許可されていません。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"画面を固定しました"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"画面固定を解除しました"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"オフライン再生を解除する前にPINの入力を求める"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index f642062..f0b3f31 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"აპს შეეძლება მოიძიოს, გამოიკვლიოს და წაშალოს შეტყობინებები, მათ შორის სხვა აპების მიერ გამოქვეყნებული."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"შეტყობინებების მოსმენის სერვისთან დაკავშირება"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"მფლობელს შეეძლება შეტყობინებების მსმენლის სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არ უნდა მოხდეს მისი გამოყენება ჩვეუელებრივი აპებისთვის.ფ"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"აკავშირებს შერჩეულ სამიზნე მომსახურებასთან"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"საშუალებას აძლევს მფლობელს, დააკავშიროს ზედა დონის ინტერფეისი შერჩეულ სამიზნე მომსახურებასთან. არასდროს უნდა იყოს საჭირო ნორმალურ აპლიკაციებში."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"მდგომარეობის პროვაიდერის სერვისებთან შეკავშირება"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"მფლობელს შეეძლება შეკავშირდეს მდგომარეობის პროვაიდერის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"მედიის მარშრუტის სერვისთან შეკავშირება"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"არ ჩართოთ ახალი აპი."</string>
     <string name="new_app_action" msgid="5472756926945440706">"დასაწყისი <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"შეაჩერე ძველი აპი ცვლილებების შენახვის გარეშე."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"შეარჩიეთ ქმედება ტექსტისთვის."</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"მრეკავის ხმა"</string>
     <string name="volume_music" msgid="5421651157138628171">"მედიის ხმა"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">ხელახლა სცადეთ 1 წამში</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"სცადეთ მოგვიანებით"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ჩამოასრიალეთ ზევიდან სრული ეკრანის დასახურად."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"სრულ ეკრანზე ნახვა"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"გამოსვლისათვის, გაასრიალეთ ზემოდან ქვემოთ."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"გასაგებია"</string>
     <string name="done_label" msgid="2093726099505892398">"დასრულდა"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"საათების წრიული სლაიდერი"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"წუთების წრიული სლაიდერი"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"მიმაგრების გასაუქმებლად ერთდროულად შეეხეთ და არ აუშვათ ღილაკებს „უკან“ და „მიმოხილვა“."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ამ ეკრანისთვის მიმაგრების გასაუქმებლად, შეეხეთ და არ აუშვათ „მიმოხილვა“-ს."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ეკრანი დაფიქსირებული. ფიქსაციის მოხსნა თქვენო ორგანიზაციის მიერ ნებადართული არ არის."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ეკრანი დაფიქსირდა"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ეკრანს ფიქსაცია მოეხსნა"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 7ce44de..3d52607 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Қолданбаға хабарларды алу, тексеру және тазалау мүмкіндігін береді, басқа қолданбалар арқылы қойылған хабарларды қоса."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"хабар тыңдау қызметіне қосылу"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Пайдаланушыға хабар есту қызметінің жоғары деңгейлі интерфейсіне жалғану мүмкіндігін ұсынады. Қалыпты қолданбаны ешқашан қажет етпеуі тиіс."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"таңдау мақсатты қызметіне байластыру"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Иесіне таңдау мақсатты қызметінің жоғарғы деңгейлі интерфейсіне байластыруға мүмкіндік береді. Қалыпты қолданбаларға үшін ешқашан қажет болмайды."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"шарттар провайдері қызметіне байластыру"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Пайдаланушыға шарт провайдері қызметінің жоғары деңгейлі интерфейсіне байластыруға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медианы бағыттау қызметіне байластыру"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Жаңа қолданбаны іске қоспау."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> қолданбасын қосу"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Ескі қолданбаны сақтаусыз тоқтату."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Мәтін үшін әрекет таңдау"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Қоңырау шырылының қаттылығы"</string>
     <string name="volume_music" msgid="5421651157138628171">"Meдиа дыбысының қаттылығы"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Әрекетті 1 секундтан кейін қайталаңыз</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Кейінірек қайта әрекеттеніңіз."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Толық экраннан шығу үшін саусағыңызды жоғарыдан төмен қарай жылжытыңыз."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Толық экранда көру"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Шығу үшін жоғарыдан төмен қарай жанап өтіңіз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Түсіндім"</string>
     <string name="done_label" msgid="2093726099505892398">"Орындалды"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Сағаттар айналымының қозғалтқышы"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Минут айналымын қозғалтқыш"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жұмыс <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Осы экранды босату үшін «Кері» және «Шолу» пәрмендерін бір уақытта түртіп, ұстап тұрыңыз."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Осы экранды босату үшін «Шолу» пәрменін түртіп, ұстап тұрыңыз."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Экран түйрелген. Босатуға ұйымыңыз рұқсат етпейді."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Экран түйрелді"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Экран босатылды"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Босату алдында PIN кодын сұрау"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 16f3da2..f429f59 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ឲ្យ​កម្មវិធី​ទៅ​យក ពិនិត្យ និង​សម្អាត​ការ​ជូន​ដំណឹង រួមមាន​​ប្រកាស​ដោយ​កម្មវិធី​ផ្សេងៗ។"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ចង​ទៅ​សេវាកម្ម​ស្ដាប់​ការ​ជូន​ដំណឹង"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​កម្មវិធី​ស្ដាប់​ការ​ជូន​ដំណឹង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​​ទេ។"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ចងភ្ជាប់ទៅសេវាកម្មគោលដៅជ្រើសរើស"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"អនុញ្ញាតឲ្យអ្នកប្រើចងភ្ជាប់ទៅអ៊ីនធឺហ្វេសកម្រិតខ្ពស់នៃសេវាកម្មគោលដៅជ្រើសរើស។ អាចនឹងមិនចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ភ្ជាប់​ទៅ​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​​របស់​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ភ្ជាប់​​ទៅ​សេវា​ផ្លូវ​មេឌៀ"</string>
@@ -1265,6 +1267,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"កុំ​ចាប់ផ្ដើម​កម្មវិធី​ថ្មី។"</string>
     <string name="new_app_action" msgid="5472756926945440706">"ចាប់ផ្ដើម <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"បញ្ឈប់​កម្មវិធី​ចាស់​ដោយ​មិន​រក្សាទុក"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ជ្រើស​សកម្មភាព​សម្រាប់​អត្ថបទ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"កម្រិត​សំឡេង​រោទ៍"</string>
     <string name="volume_music" msgid="5421651157138628171">"កម្រិត​សំឡេង​មេឌៀ"</string>
@@ -1778,7 +1788,9 @@
       <item quantity="one">ព្យាយាមម្តងទៀតក្នុងរយៈពេល 1 វិនាទី</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"សូម​ព្យាយាម​ម្ដងទៀត​នៅ​ពេល​ក្រោយ។"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"អូស​​​​ពីលើ​ចុះក្រោម ដើម្បី​ចេញ​ពី​ការ​បង្ហាញ​ពេញ​អេក្រង់។"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"កំពុងមើលពេញអេក្រង់"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ដើម្បីចាកចេញ សូមអូសពីលើចុះក្រោម។"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"យល់ហើយ"</string>
     <string name="done_label" msgid="2093726099505892398">"រួចរាល់"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"គ្រាប់​រំកិល​រង្វង់​ម៉ោង"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"គ្រាប់​រំកិល​រង្វង់​នាទី"</string>
@@ -1793,7 +1805,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"កន្លែង​ធ្វើការ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ដើម្បី​មិន​ភ្ជាប់​អេក្រង់​នេះ ប៉ះ ហើយ​សង្កត់​ថយក្រោយ និង​ទិដ្ឋភាព​នៅ​ពេល​តែ​មួយ។"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ដើម្បី​មិន​ភ្ជាប់​អេក្រង់​នេះ ប៉ះ ហើយ​សង្កត់​ទិដ្ឋភាព។"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"អេក្រង់​ត្រូវ​បាន​ភ្ជាប់។ ការ​ផ្ដាច់​មិន​​ត្រូវ​បាន​អនុញ្ញាត​ដោយ​ស្ថាប័ន​របស់​អ្នក។"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"បាន​ភ្ជាប់​អេក្រង់"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"មិន​បាន​ភ្ជាប់​អេក្រង់"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"សួរ​រក​កូដ PIN មុន​ពេល​ផ្ដាច់"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index ec24705..a834721 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಮೂಲಕ ಪೋಸ್ಟ್ ಮಾಡಿರುವ ಅಧಿಸೂಚನೆಗಳೂ ಸೇರಿದಂತೆ, ಅಂತಹ ಅಧಿಸೂಚನೆಗಳನ್ನು ಹಿಂಪಡೆದುಕೊಳ್ಳಲು, ಪರೀಕ್ಷಿಸಲು ಮತ್ತು ತೆರವುಗೊಳಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ಅಧಿಸೂಚನೆ ಕೇಳುಗರ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ಅಧಿಸೂಚನೆ ಕೇಳುಗ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ಆಯ್ಕೆಮಾಡುವವರ ಗುರಿ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ಆಯ್ಕೆಮಾಡುವವರ ಗುರಿ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ಕಂಡೀಶನ್‌‌ ಪೂರೈಕೆದಾರರ ಸೇವೆಯನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ಕಂಡೀಶನ್‌ ಪೂರೈಕೆದಾರರ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ಮಾಧ್ಯಮ ಮಾರ್ಗ ಸೇವೆಯನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್‌ ಪ್ರಾರಂಭಿಸಬೇಡಿ."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="new_app_description" msgid="1932143598371537340">"ಉಳಿಸದೇ ಹಳೆಯ ಅಪ್ಲಿಕೇಶನ್ ನಿಲ್ಲಿಸಿ."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ಪಠ್ಯಕ್ಕೆ ಕ್ರಿಯೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ರಿಂಗರ್ ವಾಲ್ಯೂಮ್"</string>
     <string name="volume_music" msgid="5421651157138628171">"ಮೀಡಿಯಾ ವಾಲ್ಯೂಮ್"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ಪೂರ್ಣ ಪರದೆಯನ್ನು ನಿರ್ಗಮಿಸಲು ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"ಪೂರ್ಣ ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ನಿರ್ಗಮಿಸಲು, ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ತಿಳಿಯಿತು"</string>
     <string name="done_label" msgid="2093726099505892398">"ಮುಗಿದಿದೆ"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ಗಂಟೆಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ನಿಮಿಷಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ಕೆಲಸ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ಈ ಪರದೆಯನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ‘ಹಿಂದೆ’ ಮತ್ತು ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಏಕಕಾಲದಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ಈ ಪರದೆಯನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ಪರದೆ ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ. ಅನ್‌ಪಿನ್‌ ಮಾಡಲು ನಿಮ್ಮ ಸಂಸ್ಥೆ ಅವಕಾಶ ಮಾಡಿಕೊಟ್ಟಿಲ್ಲ."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ಸ್ಕ್ರೀನ್‌ ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ಸ್ಕ್ರೀನ್‌ ಅನ್‌ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ಅನ್‌ಪಿನ್ ಮಾಡುವುದಕ್ಕೂ ಮೊದಲು ಪಿನ್‌ ಕೇಳಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a40ccac..c263ce9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"앱이 NFC(근거리 무선 통신) 태그, 카드 및 리더와 통신할 수 있도록 허용합니다."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"화면 잠금 사용 중지"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"앱이 키 잠금 및 관련 비밀번호 보안을 사용중지할 수 있도록 허용합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"지문 하드웨어 관리"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"사용할 지문 템플릿의 추가 및 삭제 메소드를 앱에서 실행하도록 허용합니다."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"지문 하드웨어 사용"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"앱에서 지문 하드웨어를 인증에 사용하도록 허용합니다."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"동기화 사용 및 사용 중지 전환"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"선택기 타겟 서비스 사용"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"권한을 가진 프로그램이 선택기 타겟 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"조건 제공자 서비스 사용"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"권한을 가진 프로그램이 조건 제공자 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"미디어 경로 서비스 사용"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"새 앱을 시작하지 마세요."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> 시작"</string>
     <string name="new_app_description" msgid="1932143598371537340">"저장하지 않고 이전 앱을 중단합니다."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"텍스트에 대한 작업 선택"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"벨소리 볼륨"</string>
     <string name="volume_music" msgid="5421651157138628171">"미디어 볼륨"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="one">1초 후에 다시 시도하세요.</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"나중에 다시 시도"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"전체화면을 종료하려면 위에서 아래로 스와이프하세요."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"전체 화면 보기"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"종료하려면 위에서 아래로 스와이프합니다."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"확인"</string>
     <string name="done_label" msgid="2093726099505892398">"완료"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"시간 원형 슬라이더"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"분 원형 슬라이더"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"화면 고정을 해제하려면 \'뒤로\'와 \'개요\'를 동시에 길게 터치합니다."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"화면 고정을 해제하려면 \'개요\'를 길게 터치합니다."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"화면이 고정되었습니다. 소속된 조직에서 고정 해제를 허용하지 않습니다."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"화면 고정됨"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"화면 고정 해제됨"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index faa69e6..f8a1e48 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1007,6 +1007,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Колдонмого (башка колдонмолор жайгаштырган дагы) эскертүүлөрдү алуу, изилдөө, жана аларды тазалоо мүмкүнчүлүгүн берет."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"эскертүү тыңшагыч кызматына байланыштыруу"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ээсине эскертүү тыңшагыч кызматтын жогорку деңгээл интерфейсине туташуу мүмкүнчүлүгүн берет. Жөнөкөй колдонмолордо эч качан керектелбейт."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"тандоочунун каалоосу кызматына туташуу"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Кармоочуга тандоочунун каалоосу кызматынын жогорку деңгээл интерфейсин жалгаштырууга мүмкүндүк берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"шарт түзүүчү кызматына жалгаштыруу"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Кармоочуга шарт түзүүчү кызматтын жогорку деңгээлдеги интерфейсине жалгашуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медиа жол кызматына жалгаштыруу"</string>
@@ -1655,6 +1657,14 @@
     <!-- no translation found for new_app_action (5472756926945440706) -->
     <skip />
     <string name="new_app_description" msgid="1932143598371537340">"Эски колдонмону сактабастан токтотуу."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Текст үчүн аракет тандаңыз"</string>
     <!-- no translation found for volume_ringtone (6885421406845734650) -->
     <skip />
@@ -2291,7 +2301,9 @@
       <item quantity="one">1 секунддан кийин кайталаңыз</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Кийинчерээк кайталаңыз"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Толук экран абалынан чыгуу үчүн жогорудан төмөн сүрүңүз."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Толук экранды көрүүдө"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Чыгуу үчүн, жогурдан төмөн сүрүңүз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Түшүндүм"</string>
     <string name="done_label" msgid="2093726099505892398">"Даяр"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Саат жебеси"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Мүнөт жебеси"</string>
@@ -2306,7 +2318,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Бул экранды бошотуу үчүн Артка жана Көз жүгүртүүнү чогуу басып, кармап туруңуз."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Бул экранды бошотуу үчүн Көз жүгүртүүнү басып, кармап туруңуз."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Экран кадалды. Уюмуңуздун уруксатысыз бошото албайсыз."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Экран кадалды"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Экран бошотулду"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 80025e6..70d8c65 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນ, ກວດສອບ ແລະລຶບລ້າງການແຈ້ງເຕືອນ ຮວມທັງພວກທີ່ໂພສໂດຍແອັບຯອື່ນໆນຳ."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ເຊື່ອມໂຍງກັບບໍລິການໂຕຟັງການແຈ້ງເຕືອນ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງຜູ່ຟັງບໍລິການການແຈ້ງເຕືອນ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ຜູກ​ພັນ​ກັບ​ເປົ້າ​ໝາຍ​ການ​ບໍ​ລິ​ການ​ຜູ້​ເລືອກ"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກ​ພັນ​ກັບຕົວ​ປະ​ສານລະດັບສູງສຸດຂອງການບໍລິການເປົ້າ​ໝາຍ​ຜູ້​ເລືອກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ເຊື່ອມ​ໂຍງ​ກັບ​ບໍ​ລິ​ການ​ຜູ່​ສະ​ໜອງ​ເງື່ອນ​ໄຂ"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ອະນຸຍາດ​ໃຫ້​ເຈົ້າຂອງ​ເຊື່ອມໂຍງ​ສ່ວນຕິດຕໍ່​ລະດັບ​ສູງສຸດ​ຂອງ​ບໍ​ລິ​ການ​ສະ​ໜອງ​ເງື່ອນ​ໄຂ. ບໍ່ຈຳເປັນ​ສຳລັບ​ແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"​ເຊື່ອມ​ໂຍງ​ກັບ​ບໍ​ລິ​ການ​ເສັ້ນ​ທາງ​ມີ​ເດຍ"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"ຫ້າມເປີດແອັບຯໃໝ່."</string>
     <string name="new_app_action" msgid="5472756926945440706">"ເລີ່ມຕົ້ນ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"ຢຸດແອັບຯເກົ່າໂດຍບໍ່ຕ້ອງບັນທຶກ."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ເລືອກການເຮັດວຽກຂອງຂໍ້ຄວາມ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ລະດັບສຽງເອີ້ນເຂົ້າ"</string>
     <string name="volume_music" msgid="5421651157138628171">"ລະດັບສຽງຂອງສື່"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">ລອງໃໝ່ໃນອີກ 1 ວິນາທີ</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ລອງໃໝ່ອີກຄັ້ງໃນພາຍຫລັງ."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ປັດລົງມາຈາກທາງເທິງເພື່ອອອກຈາກໂໝດເຕັມໜ້າຈໍ."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"ການ​ເບິ່ງ​ເຕັມ​ໜ້າ​ຈໍ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ເພື່ອ​ອອກ, ຮູດ​ລົງ​ລຸ່ມ​ຈາກ​ດ້ານ​ເທິງ."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ໄດ້​ແລ້ວ"</string>
     <string name="done_label" msgid="2093726099505892398">"ແລ້ວໆ"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ໂຕໝຸນປັບຊົ່ວໂມງ"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ໂຕໝຸນປັບນາທີ"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"​ບ່ອນ​ເຮັດ​ວຽກ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ເພື່ອ​ຖອດ​ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​ນີ້, ສຳ​ຜັດປຸ່ມ ​ກັບ​ຄືນ ແລະ ພາບ​ຮວມ ຄ້າງ​ໄວ້​ພ້ອມ​ກັນ."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ເພື່ອ​ຖອດ​ການ​ປັກ​ໝຸດໜ້າ​ຈໍ​ນີ້, ສຳ​ຜັດ​ປຸ່ມ ພາບ​ຮວມ ຄ້າງ​ໄວ້."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ໜ້າ​ຈໍ​ຖືກ​ປັກ​ໝຸດ​ໄວ້. ​ອົງ​ກອນ​ຂອງ​ທ່ານບໍ່​​ອະ​ນຸ​ຍາດ​ໃຫ້​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ​ໄດ້."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​ແລ້ວ"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ຍົກ​ເລີກ​ການ​ປັກ​ໝຸນ​​ຫນ້າ​ຈໍ​ແລ້ວ"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"​ຖາມ​ຫາ PIN ກ່ອນ​ຍົກ​ເລີກ​ການປັກ​ໝຸດ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index d1c2f9a..6eda58a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -798,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"susisaistyti su pranešimų skaitymo priemonės paslauga"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leidžiama turėtojui susisaistyti su pranešimų skaitymo priemonės paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"susaistyti programą su tikslo pasirinkimo paslauga"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Savininkui leidžiama susaistyti programą su tikslo pasirinkimo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"susaistyti su sąlygos teikėjo paslauga"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Turėtojui leidžiama susaistyti programą su sąlygos teikėjo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to niekada neturėtų prireikti."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"susaistyti su medijos maršruto paslauga"</string>
@@ -1273,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nepaleiskite naujos programos."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Paleisti „<xliff:g id="OLD_APP">%1$s</xliff:g>“"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Sustabdyti seną programą jos neišsaugant."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pasirinkite teksto veiksmą"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Skambučio garsumas"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medijos garsumas"</string>
@@ -1794,7 +1804,9 @@
       <item quantity="other">Bandykite dar kartą po <xliff:g id="COUNT">%d</xliff:g> sekundžių</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Vėliau bandykite dar kartą"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Perbraukite nuo viršaus žemyn, kad išeitumėte iš viso ekrano režimo"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Peržiūrima viso ekrano režimu"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Jei norite išeiti, perbraukite žemyn iš viršaus."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Supratau"</string>
     <string name="done_label" msgid="2093726099505892398">"Atlikta"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Apskritas valandų slankiklis"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Apskritas minučių slankiklis"</string>
@@ -1809,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Jei norite atsegti šį ekraną, vienu metu palieskite ir palaikykite „Atgal“ ir „Apžvalga“."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Jei norite atsegti šį ekraną, palieskite ir palaikykite „Apžvalga“."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekranas yra prisegtas. Jūsų organizacija neleidžia jo atsegti."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrano prisegtas"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekranas atsegtas"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prašyti PIN kodo prieš atsegant"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1f48ecf..6360a42 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -797,6 +797,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"saites izveidošana ar paziņojumu uztvērēja pakalpojumu"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ļauj īpašniekam izveidot saiti ar paziņojumu uztvērēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"izveidot savienojumu ar atlasītāja mērķa pakalpojumu"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ļauj atļaujas īpašniekam izveidot savienojumu ar atlasītāja mērķa pakalpojuma augstākā līmeņa saskarni. Parastām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Saistīšana ar nosacījumu sniedzēja pakalpojumu"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ļauj īpašniekam izveidot savienojumu ar drukas nosacījumu sniedzēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"Saistīšana ar multivides datu maršrutēšanas pakalpojumu"</string>
@@ -1268,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nestartējiet jauno lietotni."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Startēt: <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Aptur vecās lietotnes darbību, neko nesaglabājot."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Izvēlieties darbību tekstam"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Zvanītāja skaļums"</string>
     <string name="volume_music" msgid="5421651157138628171">"Multivides skaļums"</string>
@@ -1785,7 +1795,9 @@
       <item quantity="other">Mēģiniet vēlreiz pēc <xliff:g id="COUNT">%d</xliff:g> sekundēm</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Vēlāk mēģiniet vēlreiz."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Lai izietu no pilnekrāna režīma, velciet no augšas uz leju."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Skatīšanās pilnekrāna režīmā"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Lai izietu, no augšdaļas velciet lejup."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Labi"</string>
     <string name="done_label" msgid="2093726099505892398">"Gatavs"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Stundu apļveida slīdnis"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minūšu apļveida slīdnis"</string>
@@ -1800,7 +1812,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbā: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Lai atspraustu šo ekrānu, vienlaicīgi pieskarieties pogām “Atpakaļ” un “Pārskats” un turiet tās."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Lai atspraustu šo ekrānu, pieskarieties pogai “Pārskats” un turiet to."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekrāns ir piesprausts. Jūsu organizācija nav atļāvusi atspraušanu."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrāns ir piesprausts"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekrāns ir atsprausts"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pirms atspraušanas pieprasīt PIN"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 4ee7a81..86e31e5 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Овозможува апликацијата да враќа, проверува и брише известувања, вклучувајќи ги и оние објавени од други апликации."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"поврзи се со услугата слушател на известувања"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Овозможува сопственикот да се поврзе со интерфејс од највисоко ниво на услугата слушател на известувања. Не треба да се користи за стандардни апликации."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"сврзи се со услугата избирач на цел"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Дозволува сопственикот да се сврзе со интерфејс од највисоко ниво на услугата избирач на цел. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"поврзување со услуга за давател на услов"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозволува сопственикот да се поврзе со интерфејс од највисоко ниво на давател на услуги за услов. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"врзува со услуга за насочување медиуми"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не стартувајте ја новата апликација."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Вклучи <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Запрете ја старата апликација без зачувување."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Избери дејство за текст"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Јачина на звук на ѕвонче"</string>
     <string name="volume_music" msgid="5421651157138628171">"Јачина на звук на медиуми"</string>
@@ -1778,7 +1788,9 @@
       <item quantity="other">Обидете се повторно по <xliff:g id="COUNT">%d</xliff:g> секунди</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Обиди се повторно подоцна"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Помини со прстот одозгора надолу да излезе од режим на цел екран."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Се прикажува на цел екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"За да излезете, повлечете одозгора надолу."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Разбрав"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Приказ на часови во кружно движење"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Приказ на минути во кружно движење"</string>
@@ -1793,7 +1805,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Работа <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"За да го откачите екранот, допрете и задржете Назад и Краток преглед во исто време."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"За да го откачите екранот, допрете и задржете Краток преглед."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екранот е закачен. Откачување не е дозволено од вашата организација."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екранот е закачен"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екранот е откачен"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Прашај за ПИН пред откачување"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index db538cd..959d0a7 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -738,9 +738,9 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"നിയർ ഫീൽഡ് കമ്മ്യൂണിക്കേഷൻ (NFC) ടാഗുകളുമായും കാർഡുകളുമായും റീഡറുകളുമായുള്ള ആശയവിനിമയത്തിന് അപ്ലിക്കേഷനുകളെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"നിങ്ങളുടെ സ്‌ക്രീൻ ലോക്ക് പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"കീലോക്കും ഏതെങ്കിലും അനുബന്ധ പാസ്‌വേഡ് സുരക്ഷയും പ്രവർത്തനരഹിതമാക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ഒരു ഇൻകമിംഗ് കോൾ സ്വീകരിക്കുമ്പോൾ ഫോൺ കീലോക്ക് പ്രവർത്തനരഹിതമാക്കുന്നു, കോൾ അവസാനിക്കുമ്പോൾ കീലോക്ക് വീണ്ടും പ്രവർത്തനക്ഷമമാകുന്നു."</string>
-    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"വിരലടയാള ഹാർഡ്‌വെയർ നിയന്ത്രിക്കുക"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ഫിംഗർപ്രിന്റ് ഹാർഡ്‌വെയർ നിയന്ത്രിക്കുക"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ഉപയോഗിക്കാനായി വിരലടയാള ടെംപ്ലേറ്റുകൾ ചേർക്കാനും ഇല്ലാതാക്കാനുമുള്ള രീതികൾ അഭ്യർത്ഥിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
-    <string name="permlab_useFingerprint" msgid="3150478619915124905">"വിരലടയാള ഹാർഡ്‌വെയർ ഉപയോഗിക്കുക"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ഫിംഗർപ്രിന്റ് ഹാർഡ്‌വെയർ ഉപയോഗിക്കുക"</string>
     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"പ്രാമാണീകരണത്തിനായി വിരലടയാളം ഉപയോഗിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യുക"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ഒരു അക്കൗണ്ടിനായി സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ആളുകൾ അപ്ലിക്കേഷൻ ഒരു അക്കൗണ്ടിൽ സമന്വയിപ്പിച്ചിട്ടുണ്ടോയെന്നത് നിർണ്ണയിക്കാൻ ഇതിനാകും."</string>
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"മറ്റ് അപ്ലിക്കേഷനുകൾ പോസ്റ്റുചെയ്‌തവയുൾപ്പെടെയുള്ള, അറിയിപ്പുകൾ വീണ്ടെടുക്കാനും പരിശോധിക്കാനും മായ്‌ക്കാനും അപ്ലിക്കേഷനുകളെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ഒരു അറിയിപ്പ് ലിസണർ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ഒരു അറിയിപ്പ് ലിസണർ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ഒരു ചൂസർ ടാർഗെറ്റ് സേവനത്തിലേക്ക് ബന്ധിപ്പിക്കുക"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ഒരു ചൂസർ ടാർഗെറ്റ് സേവനത്തിന്റെ ഉയർന്ന ലെവൽ ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഉടമയെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"കണ്ടീഷൻ പ്രൊവൈഡർ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ഒരു കണ്ടീഷൻ പ്രൊവൈഡർ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"മീഡിയ റൂട്ട് സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"പുതിയ അപ്ലിക്കേഷൻ ആരംഭിക്കരുത്."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ആരംഭിക്കുക"</string>
     <string name="new_app_description" msgid="1932143598371537340">"സംരക്ഷിക്കാതെ തന്നെ പഴയ അപ്ലിക്കേഷൻ നിർത്തുക."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"വാചകസന്ദേശത്തിനായി ഒരു പ്രവർത്തനം തിരഞ്ഞെടുക്കുക"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"റിംഗർ വോളിയം"</string>
     <string name="volume_music" msgid="5421651157138628171">"മീഡിയ വോളിയം"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">ഒരു സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"പൂർണ്ണസ്‌ക്രീനിൽനിന്നും പുറത്തുകടക്കുന്നതിന് മുകളിൽ നിന്നും താഴേക്ക് സ്വൈപ്പുചെയ്യുക."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"പൂർണ്ണ സ്‌ക്രീനിൽ കാണുന്നു"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"അവസാനിപ്പിക്കാൻ, മുകളിൽ നിന്ന് താഴോട്ട് സ്വൈപ്പുചെയ്യുക."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"മനസ്സിലായി"</string>
     <string name="done_label" msgid="2093726099505892398">"പൂർത്തിയാക്കി"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ചാക്രികമായി മണിക്കൂറുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ചാക്രികമായി മിനിറ്റുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ഔദ്യോഗികം <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ഈ സ്‌ക്രീൻ അൺപിൻ ചെയ്യാൻ \'മടങ്ങുക\', \'കാഴ്ച\' എന്നിവ ഒരേ സമയം സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ഈ സ്‌ക്രീൻ അൺപിൻ ചെയ്യാൻ, കാഴ്ച സ്‌പർശിച്ച് പിടിക്കുക."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"സ്ക്രീൻ പിൻ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ ഓർഗനൈസേഷൻ അൺപിൻ ചെയ്യൽ അനുവദിക്കുന്നില്ല."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"സ്ക്രീൻ പിൻ ചെയ്തു"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"സ്ക്രീൻ അൺപിൻ ചെയ്തു"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പിൻ ആവശ്യപ്പെടുക"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 9839ff1..ba53123 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Апп нь бусад апп-уудын илгээсэн мэдэгдлүүдийг дуудах, шалгах, болон цэвэрлэх боломжтой."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"мэдэгдэл сонсогч үйлчилгээтэй холбох"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Эзэмшигч нь мэдэгдэл сонсох үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Сонгогчийн зорилтот үйлчилгээнд холбогдох"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Эзэмшигчид сонгогчийн зорилтот үйлчилгээний дээд түвшний интерфэйс рүү холбогдох боломжийг олгоно. Энэ нь энгийн апп-уудад огт шаардлагагүй."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"нөхцөл нийлүүлэгч үйлчилгээнд холбох"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Эзэмшигчид нөхцөл нийлүүлэгч үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медиа маршрут үйлчилгээтэй холбох"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Шинэ апп-г эхлүүлж болохгүй."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> эхлүүлэх"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Хуучин апп-г хадгалахгүйгээр зогсооно уу."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Текст илгээх үйлдлийг сонгох"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Хонхны аяны хэмжээ"</string>
     <string name="volume_music" msgid="5421651157138628171">"Медиа дууны хэмжээ"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 секундын дараа дахин оролдоно уу</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Дараа дахин оролдоно уу"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Бүтэн дэлгэцээс гарахын тулд дээрээс нь доош шудрана уу."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Бүтэн дэлгэцээр үзэж байна"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Гарахаар бол дээрээс нь доош нь чирнэ үү."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ойлголоо"</string>
     <string name="done_label" msgid="2093726099505892398">"Дууссан"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Цаг гүйлгэгч"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Минут гүйлгэгч"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Энэ дэлгэцийг цуцлахын тулд Буцах болон Тойм-д зэрэг хүрч барина."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Энэ дэлгэцийг цуцлахын тулд Тойм харагдацанд хүрч барина."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Дэлгэцийг тогтоосон. Дэлгэц суллахыг таны байгууллага зөвшөөрөөгүй."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Дэлгэцийг тогтоосон"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Дэлгэцийг сулласан"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 493ae99..884687e 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"अनुप्रयोगाला इतर अ‍ॅप्‍सद्वारे पोस्‍ट केलेल्‍यांसह पुनर्प्राप्त करण्‍याची, तपासण्‍याची आणि सूचना साफ करण्‍याची अनुमती देते."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना ऐकणार्‍या सेवेशी प्रतिबद्ध"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"होल्‍डरला सूचना ऐकणार्‍या सेवेच्‍या शीर्ष-दर्जाच्या इंटरफेसशी प्रतिबद्ध करण्‍याची अनुमती देते. सामान्‍य अ‍ॅप्‍ससाठी कधीही आवश्‍यक नसावे."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"एका निवडकर्ता लक्ष्य सेवेसाठी प्रतिबद्ध करा"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"धारकास निवडकर्ता लक्ष्य सेवेच्या शीर्ष-स्‍तराच्या इंटरफेसशी प्रतिबद्ध करण्‍यास अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"एका अट प्रदाता सेवेवर प्रतिबद्ध करा"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"स्थिती प्रदाता सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मीडिया मार्ग सेवेशी प्रतिबद्ध व्हा"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"नवीन अॅप प्रारंभ करू नका."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करा"</string>
     <string name="new_app_description" msgid="1932143598371537340">"जतन न करता जुना अॅप थांबवा."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"मजकुरासाठी क्रिया निवडा"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर व्हॉल्यूम"</string>
     <string name="volume_music" msgid="5421651157138628171">"मीडिया व्हॉल्यूम"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"नंतर पुन्हा प्रयत्न करा"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्ण स्क्रीनमधून निर्गमन करण्‍यासाठी शीर्षावरून खाली स्‍वाइप करा."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन पाहत आहे"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"बाहेर पडण्यासाठी, वरून खाली स्वाइप करा."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"समजले"</string>
     <string name="done_label" msgid="2093726099505892398">"पूर्ण झाले"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"तास परिपत्रक स्लायडर"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"मिनिटे परिपत्रक स्लायडर"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ही स्क्रीन अनपिन करण्यासाठी, एकाच वेळी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ही स्क्रीन अनपिन करण्यासाठी, विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्क्रीन पिन केली आहे. आपल्या संस्थेद्वारे अनपिन करण्यास अनुमती नाही."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रीन अनपिन केली"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करण्‍यापूर्वी पिन साठी विचारा"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index b512d96..255d2e8 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pendengar pemberitahuan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"terikat kepada perkhidmatan sasaran pemilih"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan sasaran pemilih. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"terikat kepada perkhidmatan pembekal keadaan"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pembekal keadaan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"terikat kepada perkhidmatan laluan media"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Jangan mulakan apl baharu."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Mulakan <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pilih tindakan untuk teks"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Kelantangan pendering"</string>
     <string name="volume_music" msgid="5421651157138628171">"Kelantangan media"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Cuba lagi dalam masa 1 saat</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Cuba sebentar lagi"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Leret ke bawah dari atas untuk keluar dari skrin penuh."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Melihat skrin penuh"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, leret dari atas ke bawah."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Faham"</string>
     <string name="done_label" msgid="2093726099505892398">"Selesai"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Penggelangsar bulatan jam"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Penggelangsar bulatan minit"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kerja <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk menyahsemat skrin ini, sentuh dan tahan Kembali serta Ikhtisar pada masa yang sama."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Untuk menyahsemat skrin ini, sentuh dan tahan Ikhtisar."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skrin disemat. Menyahsemat tidak dibenarkan oleh organisasi anda."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skrin disemat"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skrin dinyahsemat"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 7ed089c..bf4e321 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"အပလီကေးရှင်းကို အကြောင်းကြားချက်များအား ထုတ်လုပ်ရန်၊ လေ့လာရန်၊ ဖျက်ပစ်ရန် ခွင့်ပြုခြင်း။ တခြား အပလီကေးရှင်းများမှ သတိပေးချက်များလည်း ပါဝင်ပါသည်"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"သတိပေးချက် နားထောင်ခြင်း ဆားဗစ် နှင့် ပူးပေါင်းခြင်း"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ဖုန်းကိုင်ထားသူနှင့် အကြောင်းကြားချက် နားစွင့်သော ဆားဗစ်မှ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးခြင်း။ ပုံမှန် အပလီကေးရှင်းများမှာ မလိုအပ်ပါ"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ရွေးချယ်သူဦးစားပေး ဝန်ဆောင်မှုနှင့် ပူးပေါင်းခြင်း"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"လက်ဝယ်ရှိသူအား ရွေးချယ်သူဦးစားပေး ဝန်ဆောင်မှု၏ ထိပ်သီးအဆင့် အင်တာဖေ့စ်သို့ ချိတ်တွဲခွင့်ပြုပါ။ သာမန် app များ အတွက် မည်သည့်အခါမျှ မလိုအပ်ပါ။"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"အခြေအနေ စီမံပေးရေး ဝန်ဆောင်မှု တစ်ခုဆီသို့ ချိတ်တွဲခြင်း"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"စွဲကိုင်ထားသူအား အခြေအနေကို စီမံပေးသူ၏ ထိပ်သီး အဆင့် အင်တာဖေ့စ်သို့ ချိတ်တွဲခွင့်ကို ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"မီဒီယာ လမ်းကြောင်း ဝန်ဆောင်မှုသို့ တွဲချည်ရန်"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"pp အသစ်ကို မစတင်ပါနှင့်။"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>စတင်ပါ"</string>
     <string name="new_app_description" msgid="1932143598371537340">"app အဟောင်းကို မသိမ်းဆည်းဘဲ ရပ်လိုက်ပါ။"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"စာတိုအတွက် လုပ်ဆောင်ချက် ရေးပါ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ဖုန်းမြည်သံအတိုးအကျယ်"</string>
     <string name="volume_music" msgid="5421651157138628171">"မီဒီယာအသံအတိုးအကျယ်"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 စက္ကန့်အတွင်း ထပ်မံကြိုးစားပါ</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"နောက်မှ ပြန်ကြိုးစားပါ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"မျက်နှာပြင်အပြည့်ကနေ ပြန်ပြောင်းရန် အပေါ်အောက် ဆွဲချပါ"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"မျက်နှာပြင်အပြည့် ကြည့်နေစဉ်"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ထွက်ရန်၊ ထိပ်ဘက်မှ အောက်ဘက်သို့ ဆွဲချပါ။"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ရပါပြီ"</string>
     <string name="done_label" msgid="2093726099505892398">"ပြီးပါပြီ"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"နာရီရွေးချက်စရာ"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"မိနစ်လှည့်သော ရွေ့လျားတန်"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"အလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန်၊ နောက်သို့ နှင့် ခြုံကြည့်မှု ခလုတ်များကို တစ်ချိန်တည်း ထိကိုင်ထားပါ။"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန် ခြုံကြည့်မှု ခလုတ်ကို ထိကိုင်ထားပါ။"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"မျက်နှာပြင်ကို ပင်ထိုးထားသည်။ ပင်ထိုးထားမှု ဖြုတ်ခြင်းကို သင့် အဖွဲ့အစည်းက ခွင့် မပြုပါ။"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"မျက်နှာပြင်ကို ပင်ထိုးထား"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"မျက်နှာပြင် ပင်ထိုးမှု ဖြတ်လိုက်ပြီ"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f466da0..01415c0 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binding til en varsellyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lar innehaveren binde seg til det øverste grensesnittnivået for en varsellyttertjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"velge om de vil binde seg til målrettingstjenester"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Lar innehavere velge om de vil binde seg til toppnivået av grensesnittet i målrettingstjenester. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binde seg til en leverandørtjeneste for betingelser"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en leverandørtjeneste for betingelser. Dette skal ikke være nødvendig for vanlige apper."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binde seg til en mediarutingstjeneste"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ikke start den nye appen."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stopp den gamle appen uten å lagre."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Velg handling for tekst"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringetonevolum"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medievolum"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Prøv på nytt om 1 sekund</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Prøv på nytt senere"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Sveip ned fra toppen av skjermen for å gå ut av fullskjermvisningen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visning i fullskjerm"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Sveip ned fra toppen for å avslutte."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Skjønner"</string>
     <string name="done_label" msgid="2093726099505892398">"Ferdig"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Sirkulær glidebryter for timer"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Sirkulær glidebryter for minutter"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Jobb-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Tilbake og Oversikt samtidig."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Oversikt."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skjermen er festet. Løsning er ikke tillatt av organisasjonen din."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skjermen er festet"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skjermen er løsnet"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Krev PIN-kode for å løsne apper"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 1d2e442..a5558aa 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"अन्य अनुप्रयोगहरूबाट पोस्ट गरिएकासहित पुनःप्राप्त गर्न, परीक्षण गर्न र सूचनाहरू हटाउन अनुप्रयोगहरूलाई अनुमति दिन्छ।"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"जानकारी श्रोता सेवामा बाँध्नुहोस्"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"होल्डरलाई सूचना श्रोता सेवाको शीर्ष-स्तरको इन्टरफेस बाँध्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूलाई कहिले पनि आवश्यक नपर्न सक्दछ।"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"एक चयनकर्ता लक्षित सेवामा बाँध्नुहोस्"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"होल्डरलाई चयनकर्ता लक्षित सेवाको शीर्ष-स्तर इन्टरफेस बाँध्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"सर्त प्रदायक सेवामा जोड्न"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"सर्त प्रदायक सेवाको माथिल्लो स्तरको इन्टरफेसमा जोड्न बाहकलाई अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मिडिया मार्ग सेवासँग बाँध्नुहोस्"</string>
@@ -1269,6 +1271,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"नयाँ अनुप्रयोग सुरु नगर्नुहोस्।"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> सुरु गर्नुहोस्"</string>
     <string name="new_app_description" msgid="1932143598371537340">"बचत नगरी पुरानो अनुप्रयोग रोक्नुहोस्।"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"पाठको लागि एउटा प्रकार्य छान्नुहोस्"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"बजाउने मात्रा"</string>
     <string name="volume_music" msgid="5421651157138628171">"मिडियाको मात्रा"</string>
@@ -1782,7 +1792,9 @@
       <item quantity="one">1 सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"पछि पुनः प्रयास गर्नुहोस्"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्णस्क्रिनबाट बाहिर निस्कन माथिबाट तलतिर स्वाइप गर्नुहोस्।"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"पूरा पर्दा हेर्दै"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"बाहिर निस्कन, माथिबाट तल स्वाइप गर्नुहोस्।"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"बुझेँ"</string>
     <string name="done_label" msgid="2093726099505892398">"भयो"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"घण्टा गोलाकार स्लाइडर"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"मिनेट गोलाकार स्लाइडर"</string>
@@ -1797,7 +1809,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"यस पर्दालाई अनपिन गर्न एकै समय फिर्ता र सारांशलाई छोई पक्डिनुहोस्।"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"यस पर्दालाई अनपिन गर्न सारांशलाई छुनुहोस् र पक्डनुहोस्।"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्क्रिन अनपिन हुँदैछ। अनपिन गर्ने तपाईँको संगठन द्वारा समर्थित छैन।"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रिन पिन गरियो"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रिन अनपिन गरियो"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 2b4fe56..7352267 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -196,9 +196,9 @@
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stille modus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Geluid is UIT"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Geluid is AAN"</string>
-    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string>
-    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
-    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
+    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegtuigmodus"</string>
+    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string>
+    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is UIT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Instellingen"</string>
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"koppelen aan een listener-service voor meldingen"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Hiermee kan de houder koppelen aan de hoofdinterface van een listener-service voor meldingen. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"verbinding maken met een doelservice voor kiezers"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Hiermee kan de houder verbinding maken met de hoofdinterface van een doelservice voor kiezers. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binden aan de service van een provider van voorwaarden"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Hiermee kan de houder binden aan de hoofdinterface van de service van een provider van voorwaarden. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binden aan een service voor mediaroutering"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"De nieuwe app niet starten."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
     <string name="new_app_description" msgid="1932143598371537340">"De oude app stoppen zonder opslaan."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Een actie voor tekst selecteren"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Probeer het over 1 seconde opnieuw</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Probeer het later opnieuw"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Veeg omlaag vanaf de bovenkant om het volledige scherm te sluiten."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Volledig scherm wordt weergegeven"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Veeg omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ik snap het"</string>
     <string name="done_label" msgid="2093726099505892398">"Gereed"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ronde schuifregelaar voor uren"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Ronde schuifregelaar voor minuten"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Blijf \'Terug\' en \'Overzicht\' tegelijk aanraken om dit scherm los te maken."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Blijf \'Overzicht\' aanraken om dit scherm los te maken."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Scherm is vastgezet. Losmaken is niet toegestaan door uw organisatie."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Scherm vastgezet"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Scherm losgemaakt"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vragen om pincode voordat items worden losgemaakt"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index feebdba..4816897 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -798,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"utwórz połączenie z usługą odbiornika powiadomień"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi odbiornika powiadomień. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"powiązanie z usługą docelową wybierania"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umożliwia posiadaczowi tworzenie powiązania z interfejsem najwyższego poziomu usługi docelowej wybierania. Zwykłe aplikacje nie powinny potrzebować tego uprawnienia."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"powiąż z usługą dostawcy warunków"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi dostawcy warunków. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"powiązanie z usługą kierowania multimediów"</string>
@@ -1273,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nie uruchamiaj nowej aplikacji."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Uruchom <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zatrzymaj starą aplikację bez zapisywania."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Wybierz czynność, jaka ma zostać wykonana na tekście"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Głośność dzwonka"</string>
     <string name="volume_music" msgid="5421651157138628171">"Głośność multimediów"</string>
@@ -1794,7 +1804,9 @@
       <item quantity="one">Spróbuj ponownie za sekundę</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Spróbuj ponownie później"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Przesuń z góry w dół, by zamknąć pełny ekran."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Widok na pełnym ekranie"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Aby wyjść, przesuń palcem z góry na dół."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Gotowe"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kołowy suwak godzin"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kołowy suwak minut"</string>
@@ -1809,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (praca)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Aby odpiąć ten ekran, naciśnij i przytrzymaj jednocześnie Wstecz i Przegląd."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Aby odpiąć ten ekran, naciśnij i przytrzymaj Przegląd."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran jest przypięty. Ustawienia organizacji nie pozwalają go odpiąć."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran przypięty"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran odpięty"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Aby odpiąć, poproś o PIN"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4668792..18d498e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a um serviço de escuta de notificações"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o titular vincule a interface de nível superior de um serviço de escuta de notificações. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a um serviço de destino do selecionador"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao detentor ficar vinculado à interface de nível superior de um serviço de destino do selecionador. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a um serviço de fornecedor de condição"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o titular vincule a interface de nível superior de um serviço de fornecedor de condição. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a um serviço de encaminhamento multimédia"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Não iniciar a nova aplicação."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Parar a aplicação antiga sem guardar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Escolha uma ação para o texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume de multimédia"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Tente novamente dentro de 1 segundo</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Tente novamente mais tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Deslize rapidamente para baixo para sair do ecrã inteiro."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualização de ecrã inteiro"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para sair, deslize rapidamente para baixo a partir da parte superior."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Compreendi"</string>
     <string name="done_label" msgid="2093726099505892398">"Concluído"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Controlo de deslize circular das horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Controlo de deslize circular dos minutos"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar este ecrã, toque sem soltar em Retroceder e Visão geral em simultâneo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para soltar este ecrã, toque sem soltar em Visão geral."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"O ecrã está fixo. A sua entidade não o(a) autoriza a soltá-lo."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ecrã fixo"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ecrã solto"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de soltar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 0c9b2ba..14733e0 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que o app se comunique com leitores, cartões e etiqueta NFC (Comunicação a curta distância)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desativar o bloqueio de tela"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que o app desative o bloqueio de teclas e qualquer segurança por senha associada. Por exemplo, o telefone desativa o bloqueio de telas ao receber uma chamada e o reativa quando a chamada é finalizada."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gerenciar hardware de impressão digital"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que o app execute métodos para adicionar e excluir modelos de impressão digital para uso."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"usar hardware de impressão digital"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que o app use hardware de impressão digital para autenticação."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ativar e desativar sincronização"</string>
@@ -800,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o app recupere, examine e limpe notificações, inclusive as postadas por outros apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o proprietário sujeite a interface de nível superior a um serviço ouvinte de notificações. Não deve ser necessário para apps comuns."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"associar a um serviço seletor alvo"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite que o sistema se associe à interface de nível superior de um serviço seletor alvo. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"associar a um serviço provedor de condições"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o proprietário use a interface de nível superior de um serviço provedor de condições. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"usar serviço de roteamento de mídia"</string>
@@ -1267,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Não inicie o novo app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Parar o app antigo sem salvar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Escolha uma ação para o texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume da mídia"</string>
@@ -1780,7 +1786,9 @@
       <item quantity="other">Tente novamente em <xliff:g id="COUNT">%d</xliff:g> segundos</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Tente novamente mais tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Deslize de cima para baixo para sair da tela inteira"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualização em tela cheia"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para sair, deslize de cima para baixo."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendi"</string>
     <string name="done_label" msgid="2093726099505892398">"Concluído"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Controle deslizante circular das horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Controle deslizante circular dos minutos"</string>
@@ -1795,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para liberar esta tela, toque e mantenha pressionados \"Voltar\" e \"Visão geral\" ao mesmo tempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para liberar esta tela, toque e mantenha pressionado \"Visão geral\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A tela está fixada. A liberação não é permitida por sua organização."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Tela liberada"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0dda24e..dd87d74 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -797,6 +797,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"se conectează la un serviciu de alegere a țintei"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite aplicației să se conecteze la interfața de nivel superior a unui serviciu de alegere a țintei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"conectare la un serviciu furnizor de condiții"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu furnizor de condiții. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"se conectează la un serviciu de trasee multimedia"</string>
@@ -1268,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nu porniţi aplicaţia nouă."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Porniţi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Opriţi vechea aplicaţie fără să salvaţi."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Alegeţi o acţiune pentru text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volum sonerie"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volum media"</string>
@@ -1785,7 +1795,9 @@
       <item quantity="one">Reîncercați într-o secundă</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Reîncercați mai târziu"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Glisați în jos pentru a ieși din ecran complet."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Vizualizare pe ecran complet"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Pentru a ieși, glisați de sus în jos."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Am înțeles"</string>
     <string name="done_label" msgid="2093726099505892398">"Terminat"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Selector circular pentru ore"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Selector circular pentru minute"</string>
@@ -1800,7 +1812,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de serviciu"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pentru a anula fixarea pe ecran, apăsați lung, simultan, pe Înapoi și pe Vizualizare generală."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pentru a anula fixarea pe ecran, apăsați lung pe Vizualizare generală."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ecranul este fixat. Anularea fixării nu este permisă de organizația dvs."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ecran fixat"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Fixarea ecranului anulată"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 61464e6..a03d02d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -740,14 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Приложение сможет обмениваться данными с NFC-метками, картами и устройствами считывания, используя связь малого радиуса действия."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Отключение функции блокировки экрана"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Приложение сможет отключать блокировку экрана и другие функции защиты. Например, блокировка экрана будет отключаться при получении входящего вызова и включаться после завершения разговора."</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"управление сканером отпечатков"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Приложение сможет добавлять и удалять шаблоны отпечатков пальцев."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"использование сканера отпечатков"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Приложение сможет использовать сканер отпечатков пальцев для аутентификации."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Просмотр настроек синхронизации"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Включение/выключение синхронизации"</string>
@@ -802,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Подключение к сервису выбора цели"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Подключение к базовому интерфейсу для выбора цели. Это разрешение не требуется для работы обычных приложений."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Подключение к серверам поставщиков условий"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Приложение сможет подключаться к базовому интерфейсу поставщиков условий. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"Привязка к средству передачи медиафайлов"</string>
@@ -1277,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не запускать новое приложение."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Запустить приложение <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Остановить старое приложение без сохранения изменений."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Выберите действие для текста"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Громкость звонка"</string>
     <string name="volume_music" msgid="5421651157138628171">"Громкость мультимедиа"</string>
@@ -1798,7 +1804,9 @@
       <item quantity="other">Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> секунд</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Повторите попытку позже."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Чтобы вернуться в обычный режим, проведите пальцем вниз."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Полноэкранный режим"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Чтобы выйти, проведите по экрану сверху вниз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ОК"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Выбор часов на циферблате"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Выбор минут на циферблате"</string>
@@ -1813,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Рабочий <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Чтобы открепить экран, нажмите и удерживайте кнопки \"Назад\" и \"Обзор\" одновременно."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Чтобы открепить экран, нажмите и удерживайте кнопку \"Обзор\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Блокировка включена. Ее отключение запрещено правилами организации."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Блокировка включена"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Блокировка выключена"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запрашивать PIN-код для отключения блокировки"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 960fb1e..8e04673 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -739,7 +739,7 @@
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ඔබගේ තිරයේ අගුල අබල කරන්න"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"යතුරු අගුල සහ ඕනෑම සම්බන්ධිත මුරපද ආරක්ෂාවක් අබල කිරීමට යෙදුමට අවසර දෙන්න. මෙහි උදාහරණයක් වන්නේ පැමිණෙන ඇමතුමක් ලැබෙද්දී, දුරකථනය අක්‍රිය වන අතර ඇමතුම අවසාන වන විට යතුරු අගුල නැවත සක්‍රිය වෙයි."</string>
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ඇඟිලි සලකුණු දෘඩාංග කළමනාකරණය කිරීම."</string>
-    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ඇඟිලි සලකුණු සැකිලි එක් කිරීමට සහ ඉවත් කිරීමට අදාළ විධික්‍රම භාවිතය සඳහා මෙම යෙදුමට අවසර දෙයි."</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ඇඟිලි සලකුණු සැකිලි එකතු කිරීමට සහ ඉවත් කිරීමට අදාළ විධික්‍රම භාවිතය සඳහා මෙම යෙදුමට අවසර දෙයි."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"ඇඟිලි සලකුණු දෘඩාංග භාවිතා කරන්න."</string>
     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"අනන්‍යතාවය තහවුරු කරගැනීමට ඇඟිලි සලකුණු දෘඩාංග භාවිතා කිරීමට මෙම යෙදුමට ඉඩ දෙන්න."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"සමමුහුර්ත සැකසීම් කියවන්න"</string>
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"වෙනත් යෙදුම් විසින් කළ පල කිරීම්ද ඇතුළත්ව දැන්වීම් ලබා ගැනීමට, පරීක්ෂා කිරීමට සහ හිස් කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"දැනුම්දීම ඇහුම්කන් දීම් සේවාවක් වෙත බඳින්න"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"දැනුම්දීම් අසන්නාගේ සේවාවේ ඉහළ මට්ටමේ අතුරුමුහුණතට බැඳීමට දරන්නාට අවසර දේ. සාමාන්‍ය යෙදුම් සඳහා කිසිසේත් අවශ්‍ය නොවේ."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"තෝරන්නා ඉලක්ක කරගත් සේවාවකට සම්බන්ධ කරන්න"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"තෝරන්නා ඉලක්ක කරගත් සේවාවක ඉහළ මට්ට‍‍‍මේ අතුරු මුහුණත වෙත සම්බන්ධ වීමට ධාරකයාට ඉඩ‍‍දෙන්න. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවනු ඇත."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"තත්ත්වය සපයන්නාගේ සේවාවට බඳින්න"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"තත්ත්වය සපයන්නාගේ සේවාවට ඉහළ-මට්ටමේ අතුරු මුහුණතක් බැඳිමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම් සඳහා කවදාවත් අවශ්‍යය නොවෙයි."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"මාධ්‍ය ගමන් කරන සේවාව බඳින්න"</string>
@@ -1265,6 +1267,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"නව යෙදුම ආරම්භ නොකරන්න."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> අරඹන්න"</string>
     <string name="new_app_description" msgid="1932143598371537340">"සුරැකීමකින් තොරව පරණ යෙදුම නවත්වන්න."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"පෙළ සඳහා ක්‍රියාව තෝරන්න"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"හඬ නඟනයේ ශබ්දය"</string>
     <string name="volume_music" msgid="5421651157138628171">"මාධ්‍ය ශබ්දය"</string>
@@ -1778,7 +1788,9 @@
       <item quantity="other">තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සාහ කරන්න</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"පසුව නැවත උත්සාහ කරන්න"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"උඩ සිට පහළට ස්වයිප් කර පූර්ණ තිරයෙන් ඉවත්වන්න."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"මුළු තිරය ​​නරඹමින්"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ඉවත් වීමට, ඉහළ සිට පහළට ස්වයිප් කරන්න"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"වැටහුණි"</string>
     <string name="done_label" msgid="2093726099505892398">"අවසන්"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"පැය කවාකාර සර්පනය"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"මිනිත්තු කවාකාර සර්පනය"</string>
@@ -1793,7 +1805,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, ආපසු සහ දළ විශ්ලේෂණය එකම වේලාවේ ස්පර්ශ කර අල්ලා සිටින්න."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, දළ විශ්ලේෂණය ස්පර්ශ කර අල්ලා සිටින්න."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"තිරය අගුළු දමා ඇත. ඔබගේ සංවිධානය විසින් අගුළු ඇරීමට ඉඩ නොදෙයි."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"තිරය අගුළු දමා ඇත"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"තිරයේ අගුළු ඇර ඇත"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ගැලවීමට පෙර PIN විමසන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index bae9b63..60cb662 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -798,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň služby na počúvanie upozornení. Bežné aplikácie by toto nastavenie nemali nikdy požadovať."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"viazať sa na výber cieľovej služby"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania na výber cieľovej služby. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"viazanie na službu poskytovateľa podmienky"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby poskytovateľa podmienky. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"viazanie na službu smerovania médií"</string>
@@ -1273,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nespúšťať novú aplikáciu."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Spustiť <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zastaviť starú aplikáciu bez uloženia."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Zvoľte akciu pre text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitosť vyzváňania"</string>
     <string name="volume_music" msgid="5421651157138628171">"Hlasitosť médií"</string>
@@ -1794,7 +1804,9 @@
       <item quantity="one">Skúste to znova o 1 sekundu</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Skúste to znova neskôr"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Režim celej obrazovky ukončíte posunutím nadol."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Zobrazenie na celú obrazovku"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Ukončite prejdením prstom z hornej časti nadol."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Rozumiem"</string>
     <string name="done_label" msgid="2093726099505892398">"Hotovo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kruhový posúvač hodín"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posúvač minút"</string>
@@ -1809,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Práca – <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ak chcete uvoľniť túto obrazovku, súčasne klepnite na tlačidlá Späť a Prehľad a podržte ich."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ak chcete uvoľniť túto obrazovku, klepnite na tlačidlo Prehľad a podržte ho."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Obrazovka je pripnutá. Uvoľnenie vaša organizácia nepovoľuje."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka bola pripnutá"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka bola uvoľnená"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred uvoľnením požiadať o číslo PIN"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e1f15dd..6fe00d1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -798,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"poveži se s storitvijo poslušalca obvestil"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lastniku omogoča povezovanje z vmesnikom storitve poslušalca obvestil najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"povezava s storitvijo izbirnika cilja"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Imetniku omogoča povezovanje z vmesnikom storitve izbirnika cilja najvišje ravni. Nikoli ni potrebno za navadne aplikacije."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezovanje s storitvijo ponudnika pogojev"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Imetniku omogoča povezovanje z vmesnikom storitve ponudnika pogojev najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"povezovanje s storitvijo poti predstavnosti"</string>
@@ -1273,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne zaženite nove aplikacije."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Začni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Ustavi prejšnjo aplikacijo brez shranjevanja."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Izberite dejanje za besedilo"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Glasnost zvonjenja"</string>
     <string name="volume_music" msgid="5421651157138628171">"Glasnost predstavnosti"</string>
@@ -1794,7 +1804,9 @@
       <item quantity="other">Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> sekund</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Poskusite znova pozneje"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Povlecite z vrha, da zaprete celozaslonski način."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Celozaslonski način"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Zaprete tako, da z vrha s prstom povlečete navzdol."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Razumem"</string>
     <string name="done_label" msgid="2093726099505892398">"Dokončano"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Okrogli drsnik za ure"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Okrogli drsnik za minute"</string>
@@ -1809,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za delo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Če želite odpeti ta zaslon, se hkrati dotaknite tipk Nazaj in Pregled ter ju pridržite."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Če želite odpeti ta zaslon, se dotaknite tipke Pregled in jo pridržite."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Zaslon je pripet. Vaša organizacija ne dovoli odpenjanja."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pripet"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je odpet"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred odpenjanjem vprašaj za PIN"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index ecf1958..7a753eb 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -797,6 +797,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"повежи се са циљном услугом за бирање"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа циљне услуге за бирање. Никада не би требало да буде потребна за уобичајене апликације."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"повежи са услугом добављача услова"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге добављача услова. Не би требало никада да буде потребно за уобичајене апликације."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"повезивање са услугом усмеравања медија"</string>
@@ -1268,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не покрећите нову апликацију."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Покрени <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Зауставља стару апликацију без чувања."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Изаберите радњу за текст"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Јачина звука звона"</string>
     <string name="volume_music" msgid="5421651157138628171">"Јачина звука медија"</string>
@@ -1785,7 +1795,9 @@
       <item quantity="other">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Покушајте поново касније"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Превуците прстом одозго надоле да бисте изашли из целог екрана."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Приказује се цео екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Да бисте изашли, превуците надоле одозго."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Важи"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Кружни клизач за сате"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Кружни клизач за минуте"</string>
@@ -1800,7 +1812,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> на послу"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Да бисте откачили овај екран, истовремено додирните и задржите Назад и Преглед."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Да бисте откачили овај екран, додирните и задржите Преглед."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екран је закачен. Ваша организација не дозвољава откачињање."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екран је закачен"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екран је откачен"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тражи PIN пре откачињања"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 26a1343..a47cb65 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binda till en meddelandelyssnare"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en meddelandelyssnare. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"binda till en målväljartjänst"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en målväljartjänst. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind till en leverantörstjänst"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en leverantörstjänst. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binda till medieruttjänst"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Starta inte den nya appen."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Starta <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Avbryt den gamla appen utan att spara."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Välj en åtgärd för text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringvolym"</string>
     <string name="volume_music" msgid="5421651157138628171">"Mediavolym"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Försök igen om en sekund</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Försök igen senare"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Dra nedåt om du vill avbryta fullskärmsläget."</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_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>
     <string name="minute_picker_description" msgid="8606010966873791190">"Cirkelreglage för minuter"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> för arbetet"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Om du vill lossa skärmen trycker du länge på Tillbaka och Översikt samtidigt."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Om du vill lossa skämen trycker du länge på Översikt."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skärmen är fäst. Din organisation tillåter inte att du avslutar läget."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skärmen är fäst"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skärmen är inte längre fäst"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Be om pinkod innan skärmen slutar fästas"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 82791e5..1576c67 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kusano cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bandika kwenye huduma lengwa ya mchaguaji"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Huruhusu mmiliki kubandika kwenye kiolesura cha kiwango cha juu cha huduma lengwa ya mchaguaji. Haitahitajika kamwe kwa programu za kawaida."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bandika kwenye huduma ya mtoa masharti"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Humruhusu mmiliki kubandika kwenye kiolesura cha kiwango cha juu cha huduma ya mtoa masharti. Isihitajike kamwe kwa pogramu za kawaida."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bandika kwenye huduma ya njia za sauti, picha na video."</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Usianzishe programu mpya."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Anza <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Komesha programu ya zamani bila kuhifadhi."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Chagua kitendo kwa ajili ya maandishi"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Sauti ya mlio"</string>
     <string name="volume_music" msgid="5421651157138628171">"Sauti ya media"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Jaribu tena baada ya sekunde 1</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Jaribu tena baadaye"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Telezesha kidole kwa kasi chini kuanzia juu ili uondoke kwenye skrini zima."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Unatazama skrini nzima"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Ili kuondoka, telezesha kidole chini kutoka sehemu ya juu."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Nimeelewa"</string>
     <string name="done_label" msgid="2093726099505892398">"Imekamilika"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kitelezi cha mviringo wa saa"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kitelezi cha mviringo wa dakika"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ya kazini <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ili ubanue skrini hii, gusa na ushikilie Nyuma na Muhtasari kwa wakati mmoja."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ili ubanue skrini hii, gusa na ushikilie Muhtasari."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skrini imebandikwa. Ubanduaji hauruhusiwi na shirika lako."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skrini imebandikwa"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skrini imebanduliwa"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Omba PIN kabla hujabandua"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index fe4faf0..828f36b 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"பிற பயன்பாடுகளால் இடுகையிடப்பட்ட அறிவிப்புகள் உள்பட எல்லா அறிவிப்புகளையும் பெற, பார்க்க மற்றும் அழிக்கப் பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"பயனர் தேர்வுசெய்த இடச் சேவையுடன் இணைக்கும்"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"பயனர் தேர்வுசெய்த இடச் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு, ஹோல்டரை அனுமதிக்கும். இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"நிபந்தனை வழங்குநர் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"நிபந்தனை வழங்குநர் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"மீடியா வழிச் சேவையுடன் இணைத்தல்"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"புதிய பயன்பாட்டைத் தொடங்க வேண்டாம்."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ஐத் தொடங்கு"</string>
     <string name="new_app_description" msgid="1932143598371537340">"சேமிக்காமல், பழைய பயன்பாட்டை நிறுத்தவும்."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"உரைக்கான செயலைத் தேர்வுசெய்யவும்"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ரிங்கரின் ஒலியளவு"</string>
     <string name="volume_music" msgid="5421651157138628171">"மீடியாவின் ஒலியளவு"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 வினாடி கழித்து முயற்சிக்கவும்</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"மீண்டும் முயற்சிக்கவும்"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"முழுத் திரையிலிருந்து வெளியேற மேலிருந்து கீழே ஸ்வைப் செய்யவும்."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"முழுத் திரையில் காட்டுகிறது"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"வெளியேற, மேலிருந்து கீழே ஸ்வைப் செய்யவும்"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"புரிந்தது"</string>
     <string name="done_label" msgid="2093726099505892398">"முடிந்தது"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"மணிநேர வட்ட வடிவ ஸ்லைடர்"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"நிமிடங்களுக்கான வட்டவடிவ ஸ்லைடர்"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"பணியிடம் <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"இந்தத் திரையை விலக்க, பின் மற்றும் மேலோட்டப் பார்வையை ஒரே நேரத்தில் தொட்டுப் பிடித்திருக்கவும்."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"இந்தத் திரையை விலக்க, மேலோட்டப் பார்வையைத் தொட்டுப் பிடித்திருக்கவும்."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"திரை பின் செய்யப்பட்டது. பின்னை அகற்ற உங்கள் நிறுவனம் ஆதரிக்கவில்லை."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"திரை பின் செய்யப்பட்டது"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"திரையின் பின் அகற்றப்பட்டது"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"அகற்றும் முன் PINஐக் கேள்"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index eec41de9..af672cc 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"నోటిఫికేషన్‌లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"నోటిఫికేషన్ పరిశీలన సేవకు అనుబంధించడం"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ఎంపిక లక్ష్యం సేవకు నిర్బంధించడం"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ఎంపిక లక్ష్యం సేవ అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు నిర్బంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"షరతు ప్రదాత సేవకు అనుబంధించడం"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"మీడియా మార్గ సేవకు అనుబంధించడం"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"కొత్త అనువర్తనాన్ని ప్రారంభించవద్దు."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ని ప్రారంభించండి"</string>
     <string name="new_app_description" msgid="1932143598371537340">"పాత అనువర్తనాన్ని సేవ్ చేయకుండానే ఆపివేయండి."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"వచనం కోసం చర్యను ఎంచుకోండి"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"రింగర్ వాల్యూమ్"</string>
     <string name="volume_music" msgid="5421651157138628171">"మీడియా వాల్యూమ్"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 సెకనులో మళ్లీ ప్రయత్నించండి</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"తర్వాత మళ్లీ ప్రయత్నించండి"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"పూర్తి స్క్రీన్ నుండి నిష్క్రమించడానికి పైనుండి కిందికి స్వైప్ చేయండి."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"పూర్తి స్క్రీన్‌లో వీక్షిస్తున్నారు"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"నిష్క్రమించడానికి, పై నుండి క్రిందికి స్వైప్ చేయండి."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"అర్థమైంది"</string>
     <string name="done_label" msgid="2093726099505892398">"పూర్తయింది"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"గంటల వృత్తాకార స్లయిడర్"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"నిమిషాల వృత్తాకార స్లయిడర్"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ఈ స్క్రీన్‌ను అన్‌పిన్ చేయడానికి, వెనుకకు మరియు అవలోకనం బటన్‌లను ఒకేసారి నొక్కి, ఉంచండి."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ఈ స్క్రీన్‌ని అన్‌పిన్ చేయడానికి, అవలోకనం నొక్కి, ఉంచండి."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"స్క్రీన్ పిన్ చేయబడింది. మీ సంస్థలో అన్‌పిన్ చేయడానికి అనుమతి లేదు."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"స్క్రీన్ పిన్ చేయబడింది"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"స్క్రీన్ అన్‌పిన్ చేయబడింది"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a407178..15e70c3 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"เชื่อมโยงกับบริการเป้าหมายของผู้เลือก"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"อนุญาตให้แอปเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการเป้าหมายของผู้เลือก ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"เชื่อมโยงกับบริการของผู้เสนอเงื่อนไข"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการของผู้เสนอเงื่อนไข ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"เชื่อมโยงกับบริการเส้นทางสื่อ"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"อย่าเริ่มแอปพลิเคชันใหม่"</string>
     <string name="new_app_action" msgid="5472756926945440706">"เริ่มต้น <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"หยุดการทำงานของแอปพลิเคชันเก่าโดยไม่บันทึก"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"เลือกการทำงานกับข้อความ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ระดับความดังเสียงเรียกเข้า"</string>
     <string name="volume_music" msgid="5421651157138628171">"ระดับเสียงของสื่อ"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">ลองอีกครั้งใน 1 วินาที</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ลองอีกครั้งในภายหลัง"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"กวาดนิ้วบนลงล่างเพื่อออกจากโหมดเต็มหน้าจอ"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"กำลังดูแบบเต็มหน้าจอ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"หากต้องการออกไป ให้กวาดนิ้วลงจากด้านบน"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"รับทราบ"</string>
     <string name="done_label" msgid="2093726099505892398">"เสร็จสิ้น"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ตัวเลื่อนหมุนระบุชั่วโมง"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ตัวเลื่อนหมุนระบุนาที"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g>ที่ทำงาน"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"หากต้องการเลิกตรึงหน้าจอนี้ แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้พร้อมกัน"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"หากต้องการเลิกตรึงหน้าจอ แตะ \"ภาพรวม\" ค้างไว้"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ตรึงหน้าจอแล้ว องค์กรของคุณไม่อนุญาตให้เลิกตรึง"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ตรึงหน้าจอแล้ว"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"เลิกตรึงหน้าจอแล้ว"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6e0d4fc..f19e06f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mapailalim sa isang serbisyo ng notification listener"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nagbibigay-daan sa may-ari na mapailalim sa interface sa tuktok na antas ng isang serbisyo ng notification listener. Hindi dapat kailanganin para sa karaniwang apps kahit kailan."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"sumailalim sa isang serbisyo ng chooser target"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Nagbibigay-daan sa may-ari na sumailalim sa top-level interface ng isang serbisyo ng chooser target. Hindi dapat kailanman kailanganin para sa mga karaniwang app."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"i-bind sa isang serbisyo sa pagbibigay ng kundisyon"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Nagbibigay-daan sa naghahawak na i-bind ang top-level na interface ng isang serbisyo sa pagbibigay ng kundisyon. Hindi kailanman dapat kailanganin ng mga normal na app."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"mag-bind sa isang serbisyo ng media route"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Huwag simulan ang bagong app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Simulan ang <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Ihinto ang lumang app nang hindi nagse-save."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pumili ng pagkilos para sa teksto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Lakas ng tunog ng ringer"</string>
     <string name="volume_music" msgid="5421651157138628171">"Lakas ng tunog ng media"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other">Subukang muli sa loob ng <xliff:g id="COUNT">%d</xliff:g> na segundo</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Subukang muli sa ibang pagkakataon"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Mag-swipe pababa mula sa itaas upang lumabas sa full screen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Panonood sa full screen"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Upang lumabas, mag-swipe mula sa itaas pababa."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Nakuha ko"</string>
     <string name="done_label" msgid="2093726099505892398">"Tapos na"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Pabilog na slider ng mga oras"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Pabilog na slider ng mga minuto"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Bumalik at Overview nang sabay-sabay."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Overview."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Naka-pin ang screen. Hindi pinapayagan ng iyong organisasyon ang pag-a-unpin."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Naka-pin ang screen"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Naka-unpin ang screen"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a49d93d..1b5bd6c 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirim dinleyici hizmetine bağlan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"İzin sahibine bir bildirim dinleyici hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"seçici hedef hizmetine bağlanma"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"İzin sahibine bir seçici hedef hizmetinin üst seviye arayüzüne bağlanma olanağı sunar. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bir durum sağlayıcı hizmetine bağlanma"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"İzin sahibinin, bir durum sağlayıcı hizmete ait üst düzey arayüze bağlanmasına izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bir medya yönlendirme hizmetine bağlan"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Yeni uygulamayı başlatmayın."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> uygulamasını başlat"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Kaydetmeden eski uygulamayı durdurun."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Kısa mesaj için bir işlem seçin"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Zil sesi düzeyi"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medya ses düzeyi"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 saniye içinde tekrar deneyin</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Daha sonra tekrar deneyin"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Tam ekrandan çıkmak için yukarıdan aşağıya hızlıca kaydırın."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Tam ekran olarak görüntüleme"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Çıkmak için yukarıdan aşağıya doğru hızlıca kaydırın."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Anladım"</string>
     <string name="done_label" msgid="2093726099505892398">"Bitti"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Saat kaydırma çemberi"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Dakika kaydırma çemberi"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (İş)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Bu ekranın sabitlemesini kaldırmak için Geri ve Genel Bakış\'a aynı anda dokunup basılı tutun."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Bu ekranın sabitlemesini kaldırmak için Genel Bakış\'a dokunup basılı tutun."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran sabitlendi. Kuruluşunuz sabitlemenin kaldırılmasına izin vermiyor."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran sabitlendi"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran sabitlemesi kaldırıldı"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 4fc776d..306137e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -798,6 +798,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"підключатися до цільової служби для вибору"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Додаток зможе підключатися до інтерфейсу верхнього рівня цільової служби для вибору. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"підключитися до служби постачання умов"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби постачання умов. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"підключатися до служби передавання медіафайлів"</string>
@@ -1273,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не запускати нову програму."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Запуст. <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Зупинити попередню програму без збереження."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Виберіть дію для тексту"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Гучність дзвінка"</string>
     <string name="volume_music" msgid="5421651157138628171">"Гучність медіа"</string>
@@ -1794,7 +1804,9 @@
       <item quantity="other">Повтор через <xliff:g id="COUNT">%d</xliff:g> секунди</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Спробуйте пізніше"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Проведіть пальцем зверху вниз, щоб вийти з повноекранного режиму."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Перегляд на весь екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Щоб вийти, проведіть пальцем зверху вниз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Зрозуміло"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Вибір годин на циферблаті"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Вибір хвилин на циферблаті"</string>
@@ -1809,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Робоча <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Щоб відкріпити екран, одночасно натисніть і утримуйте кнопки \"Назад\" та \"Огляд\"."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Щоб відкріпити екран, натисніть і утримуйте кнопку \"Огляд\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екран закріплено. Ваша організація заборонила відкріплювати його."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екран закріплено"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екран відкріплено"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитувати PIN-код перед відкріпленням"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index adc11a6..5967744 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"دوسرے ایپس کے ذریعے شائع کردہ کے بشمول ایپ کو اطلاعات کی بازیابی، تفتیش اور انہیں صاف کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اطلاع سننے والی سروس کے پابند بنیں"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"حامل کو اطلاع سننے والی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ایک انتخاب کنندہ کی اہدافی سروس کا پابند بنائیں"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"حامل کو ایک انتخاب کنندہ کی اہدافی سروس کے اعلی سطحی انٹرفیس کا پابند بنانے کی اجازت دیتا ہے۔ عام اطلاقات کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"شرط فراہم کرنے والی ایک سروس کے پابند بنیں"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"حامل کو شرط فراہم کنندہ کی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"میڈیا روٹ سروس کا پابند بنیں"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"نئی ایپ شروع نہ کریں۔"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> شروع کریں"</string>
     <string name="new_app_description" msgid="1932143598371537340">"محفوظ کیے بغیر پرانی ایپ بند کریں۔"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"متن کیلئے ایک کارروائی منتخب کریں"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"رنگر والیوم"</string>
     <string name="volume_music" msgid="5421651157138628171">"میڈیا والیوم"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 سیکنڈ میں دوبارہ کوشش کریں</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"بعد میں دوبارہ کوشش کریں"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"مکمل اسکرین سے نکلنے کیلئے اوپر سے نیچے سوائپ کریں۔"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"پوری اسکرین میں دیکھ رہے ہیں"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"خارج ہونے کیلئے اوپر سے نیچے سوائپ کریں۔"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"سمجھ آ گئی"</string>
     <string name="done_label" msgid="2093726099505892398">"ہو گیا"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"گھنٹوں کا سرکلر سلائیڈر"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"منٹس سرکلر سلائیڈر"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"دفتر <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"اس اسکرین سے پن ہٹانے کیلئے، واپس جائیں اور مجموعی جائزہ کو ایک ساتھ ٹچ کریں اور دبا کر رکھیں۔"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"اس اسکرین سے پن ہٹانے کیلئے، مجموعی جائزہ کو ٹچ کریں اور دبا کر رکھیں۔"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"اسکرین کو پن کر دیا گیا ہے۔ آپ کی تنظیم کی جانب سے پن ہٹانے کی اجازت نہیں ہے۔"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"اسکرین کو پن کر دیا گیا"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"اسکرین کا پن ہٹا دیا گیا"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"‏پن ہٹانے سے پہلے PIN طلب کریں"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 27237f5..812f34e 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dasturga bildirishnomalar va boshqa dasturlar jo‘natgan xabarlarni qabul qilish, ko‘rib chiqish hamda tozalash imkonini beradi."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirishnomani tinglash xizmatiga bog‘lash"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Foydalanuvchiga bildirishnomani eshituvchi xizmat yuqori darajali interfeysini bog‘lash imkonini beradi. Oddiy dasturlar uchun hech qachon kerak bo‘lmaydi."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"mo‘ljaldagi xizmat bilan bog‘lanish"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Egasiga mo‘ljaldagi xizmatning yuqori darajali interfeysiga bog‘lanish uchun ruxsat beradi. Oddiy ilovalar uchun hech qachon kerak bo‘lmaydi."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"shartlarni taqdim etuvchilarning serveriga ulanish"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ilova shartlarni taqdim etuvchining yuqori darajali interfeysiga ulanishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"media fayllarni uzatish vositasiga bog‘lab qo‘yish"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Yangi ilova ishga tushirilmasin."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ni ishga tushirish"</string>
     <string name="new_app_description" msgid="1932143598371537340">"O‘zgarishlarni saqlamasdan, eski ilova yopilsin"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Matn uchun amalni tanlash"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Qo‘ng‘iroq tovushi"</string>
     <string name="volume_music" msgid="5421651157138628171">"Media tovushi"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 soniyadan so‘ng qayta urinib ko‘ring</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Keyinroq urinib ko‘ring"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"\"Butun ekran\" usulidan chiqish uchun barmoq bilan ekran tepasidan pastga tomon silang."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"To‘liq ekran ko‘rsatilmoqda"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Chiqish uchun tepadan pastga torting."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Tayyor"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Doiradan soatni tanlang"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Doiradan daqiqani tanlang"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ish <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ushbu ekrandan chiqish uchun “Orqaga” va “Umumiy nazar” tugmalarini bir vaqtda bosib turing."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ushbu ekrandan chiqish uchun “Umumiy nazar” tugmasini bosib turing."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran qadab qo‘yildi. Uni bo‘shatishga tashkilotingiz ruxsat bermagan."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran qadab qo‘yildi"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran bo‘shatildi"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bo‘shatishdan oldin PIN kod so‘ralsin"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ce5fc5a..8c8c305 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"liên kết với dịch vụ trình xử lý thông báo"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ trình xử lý thông báo. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"liên kết với dịch vụ nhắm mục tiêu trình chọn"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ nhắm mục tiêu trình chọn. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"liên kết với dịch vụ trình cung cấp điều kiện"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ trình cung cấp điều kiện. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"liên kết với dịch vụ định tuyến phương tiện"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Không khởi động ứng dụng mới."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Bắt đầu <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Dừng ứng dụng cũ mà không lưu."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Chọn một tác vụ cho văn bản"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Âm lượng chuông"</string>
     <string name="volume_music" msgid="5421651157138628171">"Âm lượng phương tiện"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">Hãy thử lại sau 1 giây</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Hãy thử lại sau"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Vuốt từ trên xuống để thoát toàn màn hình."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Xem toàn màn hình"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Để thoát, hãy vuốt xuống từ trên cùng."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Xong"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Thanh trượt giờ hình tròn"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Thanh trượt phút hình tròn"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> làm việc"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Để bỏ khóa màn hình này, chạm và giữ Quay lại và Tổng quan cùng lúc."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Để bỏ khóa màn hình này, chạm và giữ Tổng quan."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Màn hình đã được ghim. Tổ chức của bạn không cho phép bỏ ghim."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Đã ghim màn hình"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Đã bỏ ghim màn hình"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Hỏi mã PIN trước khi bỏ ghim"</string>
diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml
new file mode 100644
index 0000000..4ea2b52
--- /dev/null
+++ b/core/res/res/values-watch/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- [CHAR LIMIT=16] Message shown in upgrading dialog for each .apk that is optimized. -->
+    <!-- Each word has an 8 character limit due to screen width limitation. -->
+    <string name="android_upgrading_apk">App
+        <xliff:g id="number" example="123">%1$d</xliff:g> of
+        <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
+</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 507e530..497a9dc 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -738,14 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"允许应用与近距离无线通信(NFC)标签、卡和读取器通信。"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"停用屏幕锁定"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"允许该应用停用键锁以及任何关联的密码安全措施。例如,让手机在接听来电时停用键锁,在通话结束后重新启用键锁。"</string>
-    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
-    <skip />
-    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
-    <skip />
-    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
-    <skip />
-    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
-    <skip />
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"管理指纹硬件"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"允许该应用调用方法来添加和删除可用的指纹模板。"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"使用指纹硬件"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"允许该应用使用指纹硬件进行身份验证"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允许该应用读取某个帐户的同步设置。例如,此权限可确定“联系人”应用是否与某个帐户同步。"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"启用和停用同步"</string>
@@ -800,6 +796,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
+    <!-- no translation found for permlab_bindChooserTargetService (3443261076710185673) -->
+    <skip />
+    <!-- no translation found for permdesc_bindChooserTargetService (1413908999583734970) -->
+    <skip />
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供程序服务"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供程序服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"绑定至媒体转接服务"</string>
@@ -1267,6 +1267,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"不启动新的应用。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"启动<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"停止旧的应用,但不保存。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"选择要对文字执行的操作"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"铃声音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"媒体音量"</string>
@@ -1780,7 +1788,12 @@
       <item quantity="one">1 秒后重试</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"稍后重试"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"从顶部向下滑动即可退出全屏模式。"</string>
+    <!-- no translation found for immersive_cling_title (8394201622932303336) -->
+    <skip />
+    <!-- no translation found for immersive_cling_description (3482371193207536040) -->
+    <skip />
+    <!-- no translation found for immersive_cling_positive (5016839404568297683) -->
+    <skip />
     <string name="done_label" msgid="2093726099505892398">"完成"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"小时转盘"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"分钟转盘"</string>
@@ -1795,7 +1808,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"要取消固定此屏幕,请同时触摸并按住“返回”和“概览”按钮。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"要取消固定此屏幕,请触摸并按住概览按钮。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"屏幕处于固定状态。您所属的单位不允许取消固定。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"已固定屏幕"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定屏幕"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index c60a1be..2f6f3fe 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (不建議一般應用程式使用)。"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"繫結至所選服務"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允許應用程式繫結至所選服務的頂層介面 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件供應商服務"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件供應商服務的頂層介面,但一般應用程式並不需要使用。"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"繫結至媒體轉送服務"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式,且不儲存。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"選擇處理文字的操作"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"鈴聲音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"媒體音量"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">1 秒後再試一次</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"稍後再試"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"由頂端往下快速滑動即可離開全螢幕。"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"開啟全螢幕"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"由上往下刷退出。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string>
     <string name="done_label" msgid="2093726099505892398">"完成"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"小時環形滑桿"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"分鐘環形滑桿"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住 [返回] 和 [概覽]。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"如要取消固定這個畫面,請輕觸並按住 [概覽]。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"螢幕已固定,而您的機構不允許取消固定。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"螢幕已固定"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6925d9f..35421ae 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"與選擇器目標服務繫結"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允許應用程式繫結至選擇器目標服務的頂層介面 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件提供者服務"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件提供者服務的頂層介面 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"繫結至媒體轉送服務"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式且不儲存。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"選取傳送文字內容的方式"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"鈴聲音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"媒體音量"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="one">請於 1 秒後再試一次</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"稍後再試"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"從頂端往下滑動即可退出全螢幕模式。"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"以全螢幕檢視"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"如要退出,請從畫面頂端向下滑動。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string>
     <string name="done_label" msgid="2093726099505892398">"完成"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"小時數環狀滑桿"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"分鐘數環狀滑桿"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住返回按鈕和總覽按鈕。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"如要取消固定這個畫面,請輕觸並按住總覽按鈕。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"螢幕已固定,且貴機構不允許取消固定。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"已固定螢幕"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 1313a5a..98b9e73d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -796,6 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bophezela kwisevisi yomlaleli wesaziso"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ivumela umbambi ukubophezela kwisixhumi esibonakalayo sezinga eliphezulu lesevisi yomlaleli wesaziso. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bophezela isevisi eqondisiwe yesikhethi"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ivumela umbambi ukuthi ahlanganise kuleveli ephezulu yesevisi yesikhethi. Akudingeki kuzinhlelo zokusebenza ezimvamile."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"hlanganisa kwisevisi yomhlinzeki wesimo"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo seleveli ephezulu sesevisi yomhlinzeki wesimo. Akufanele kudingekele izinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"hlanganisela kusevisi yomzila yemidiya"</string>
@@ -1263,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali uhlelo lokusebenza entsha."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Qala <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Misa uhlelo lokusebenza endala ngaphandle kokulondoloza."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Khetha okufanele kwenziwe okomqhafazo"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ivolumu yesishayeli"</string>
     <string name="volume_music" msgid="5421651157138628171">"Ivolumu yemidiya"</string>
@@ -1776,7 +1786,9 @@
       <item quantity="other">Zama futhi kumasekhondi angu-<xliff:g id="COUNT">%d</xliff:g></item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Zama futhi emva kwesikhathi"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swayiphela phansi kusukela phezulu ukuze uphume kusikrini esigcwele."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Ukubuka isikrini esigcwele"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Ukuze uphume, swayiphela phansi kusuka phezulu."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ngiyitholile"</string>
     <string name="done_label" msgid="2093726099505892398">"Kwenziwe"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Amahora weslayidi esiyindingilizi"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Amaminithi weslayidi esiyindingilizi"</string>
@@ -1791,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Umsebenzi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ukuze ususe ukuphina kulesi sikrini, thinta uphinde ubambe i-Emuva ne-Buka konke ngesikhathi esisodwa."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ukuze ususe ukuphina lesi sikrini, thinta uphinde ubambe Buka konke."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Isikrini siphiniwe. Ukususa ukuphina akuvumelekile inhlangano yakho."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Isikrini siphiniwe"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Isikrini sisuswe ukuphina"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Cela iphinikhodi ngaphambi kokuphina"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fd8b803..3ca88e5 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -64,26 +64,11 @@
          As of Honeycomb, blurring is not supported anymore. -->
     <bool name="config_sf_slowBlur">true</bool>
 
-    <!-- Flag indicating that the media framework should allow changing
-         master volume stream and nothing else . -->
-    <bool name="config_useMasterVolume">false</bool>
-
     <!-- Flag indicating that the media framework should support playing of sounds on volume
          key usage.  This adds noticeable additional overhead to volume key processing, so
          is disableable for products for which it is irrelevant. -->
     <bool name="config_useVolumeKeySounds">true</bool>
 
-    <!-- Array of integer pairs controlling the rate at which the master volume changes
-         in response to volume up and down key events.
-         The first integer of each pair is compared against the current master volume
-         (in range 0 to 100).
-         The last pair with first integer <= the current volume is chosen,
-         and the second integer of the pair indicates the amount to increase the master volume
-         when volume up is pressed. -->
-    <integer-array name="config_masterVolumeRamp">
-        <item>0</item>  <item>5</item>  <!-- default: always increase volume by 5% -->
-    </integer-array>
-
     <!-- The attenuation in dB applied to the sound effects played
          through AudioManager.playSoundEffect() when no volume is specified. -->
     <integer name="config_soundEffectVolumeDb">-6</integer>
@@ -530,6 +515,8 @@
     <bool name="config_allowTheaterModeWakeFromWindowLayout">false</bool>
     <!-- If this is true, go to sleep when theater mode is enabled from button press -->
     <bool name="config_goToSleepOnButtonPressTheaterMode">true</bool>
+    <!-- If this is true, long press on power button will be available from the non-interactive state -->
+    <bool name="config_supportLongPressPowerWhenNonInteractive">false</bool>
 
     <!-- Auto-rotation behavior -->
 
@@ -2093,4 +2080,7 @@
 
     <!-- Specifies the maximum burn-in offset vertically. -->
     <integer name="config_burnInProtectionMaxVerticalOffset">0</integer>
+
+    <!-- Keyguard component -->
+    <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7c745ac..bf370f4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2354,6 +2354,11 @@
     <string name="permdesc_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps.</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_bindChooserTargetService">bind to a chooser target service</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_bindChooserTargetService">Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps.</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_bindConditionProviderService">bind to a condition provider service</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_bindConditionProviderService">Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps.</string>
@@ -3710,6 +3715,23 @@
     <string name="new_app_action">Start <xliff:g id="old_app">%1$s</xliff:g></string>
     <string name="new_app_description">Stop the old app without saving.</string>
 
+    <!-- Notification text to tell the user that a process has exceeded its memory limit. -->
+    <string name="dump_heap_notification"><xliff:g id="proc">%1$s</xliff:g> exceeded memory
+        limit</string>
+
+    <!-- Notification details to tell the user that a process has exceeded its memory limit. -->
+    <string name="dump_heap_notification_detail">Heap dump has been collected;
+        touch to share</string>
+
+    <!-- Title of dialog prompting the user to share a heap dump. -->
+    <string name="dump_heap_title">Share heap dump?</string>
+
+    <!-- Text of dialog prompting the user to share a heap dump. -->
+    <string name="dump_heap_text">The process <xliff:g id="proc">%1$s</xliff:g> has exceeded
+        its process memory limit of <xliff:g id="size">%2$s</xliff:g>.  A heap dump is available
+        for you to share with its developer.  Be careful: this heap dump can contain any
+        of your personal information that the application has access to.</string>
+
     <!-- Displayed in the title of the chooser for things to do with text that
          is to be sent to another application. For example, I can send
          text through SMS or IM.  A dialog with those choices would be shown,
@@ -5055,7 +5077,7 @@
     <!-- Notify use that they are in Lock-to-app in accessibility mode -->
     <string name="lock_to_app_toast_accessible">To unpin this screen, touch and hold Overview.</string>
     <!-- Notify user that they are locked in lock-to-app mode -->
-    <string name="lock_to_app_toast_locked">Screen is pinned. Unpinning isn\'t allowed by your organization.</string>
+    <string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string>
     <!-- Starting lock-to-app indication. -->
     <string name="lock_to_app_start">Screen pinned</string>
     <!-- Exting lock-to-app indication. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e17f5fc..f16c5cf 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -274,7 +274,6 @@
   <java-symbol type="bool" name="preferences_prefer_dual_pane" />
   <java-symbol type="bool" name="skip_restoring_network_selection" />
   <java-symbol type="bool" name="split_action_bar_is_narrow" />
-  <java-symbol type="bool" name="config_useMasterVolume" />
   <java-symbol type="bool" name="config_useVolumeKeySounds" />
   <java-symbol type="bool" name="config_enableWallpaperService" />
   <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
@@ -1087,7 +1086,6 @@
   <java-symbol type="array" name="sim_colors" />
   <java-symbol type="array" name="special_locale_codes" />
   <java-symbol type="array" name="special_locale_names" />
-  <java-symbol type="array" name="config_masterVolumeRamp" />
   <java-symbol type="array" name="config_cdma_dun_supported_types" />
   <java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
   <java-symbol type="array" name="config_operatorConsideredNonRoaming" />
@@ -1605,6 +1603,7 @@
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" />
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" />
   <java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" />
+  <java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" />
   <java-symbol type="bool" name="config_wifi_background_scan_support" />
   <java-symbol type="bool" name="config_wifi_dual_band_support" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
@@ -1725,6 +1724,10 @@
   <java-symbol type="string" name="data_usage_wifi_limit_title" />
   <java-symbol type="string" name="default_wallpaper_component" />
   <java-symbol type="string" name="dlg_ok" />
+  <java-symbol type="string" name="dump_heap_notification" />
+  <java-symbol type="string" name="dump_heap_notification_detail" />
+  <java-symbol type="string" name="dump_heap_text" />
+  <java-symbol type="string" name="dump_heap_title" />
   <java-symbol type="string" name="factorytest_failed" />
   <java-symbol type="string" name="factorytest_no_action" />
   <java-symbol type="string" name="factorytest_not_system" />
@@ -2046,6 +2049,9 @@
   <java-symbol type="array" name="config_clockTickVibePattern" />
   <java-symbol type="array" name="config_calendarDateVibePattern" />
 
+  <!-- From KeyguardServiceDelegate -->
+  <java-symbol type="string" name="config_keyguardComponent" />
+
   <!-- From various Material changes -->
   <java-symbol type="attr" name="titleTextAppearance" />
   <java-symbol type="attr" name="subtitleTextAppearance" />
diff --git a/docs/html/google/play-services/wallet.jd b/docs/html/google/play-services/wallet.jd
index e5ed514..744c8d3 100644
--- a/docs/html/google/play-services/wallet.jd
+++ b/docs/html/google/play-services/wallet.jd
@@ -17,14 +17,14 @@
     available to US-based merchants. Once you've completed integration, you can
     apply for production access by <a class="external-link" href="https://support.google.com/wallet/business/contact/ui_review">submitting your sandbox integration for review</a>.</p>
 
-  <p>Check out the <a 
+  <p>Check out the <a
   href="{@docRoot}reference/com/google/android/gms/wallet/package-summary.html">Instant
   Buy API reference</a> and visit
   <a href="https://developers.google.com/wallet/instant-buy/">developers.google.com/wallet/instant-buy/</a>
   for complete information about integrating Google Wallet Instant Buy into your app.</p>
 </div>
 
-<div class="col-4"> 
+<div class="col-4">
   <img src="{@docRoot}images/google/gps-wallet-instant.png" alt="" style="padding-bottom:14px;width:210px">
 </div>
 </div>
@@ -44,16 +44,16 @@
       <h4>Streamline Purchases with Google+ Sign-On</h4>
       <p>For users ready to purchase, you can simplify the login and account creation steps
       by adding Google+ sign in. Users can sign in with a single click and share their
-      profile information during the purchase. 
+      profile information during the purchase.
       <br />
       <a href="https://developers.google.com/commerce/wallet/instant-buy/wallet-sso#android"
       class="external-link">Add Google+ Sign-In for Wallet</a>.</p>
-       
+
       <h4>Minimize User Data Entry</h4>
       <p>Google Wallet provides auto-completion of addresses, minimizing user data entry. You can also
       retrieve billing and shipping addresses directly from the user’s Wallet to-do form pre-fills.<br />
       <a class="external-link"
-      href="https://developers.google.com/commerce/wallet/instant-buy/android/reference/com/google/android/gms/wallet/MaskedWallet#getBillingAddress()">Get
+      href="{@docRoot}reference/com/google/android/gms/wallet/MaskedWallet.html#getBillingAddress()">Get
       billing addresses</a>.</p>
   </div>
 
@@ -75,7 +75,7 @@
     class="external-link" href="https://developers.google.com/wallet/instant-buy/android/tutorial">Instant Buy Android API tutorial</a>
     provides directions on how to get the Wallet sample up and running.</p>
     <h4>3. Read the documentation</h4>
-    <p>For quick access while developing your Android apps, the <a 
+    <p>For quick access while developing your Android apps, the <a
     href="{@docRoot}reference/com/google/android/gms/wallet/package-summary.html">Google Wallet
     API reference</a> is available here on developer.android.com.</p>
 
diff --git a/docs/html/guide/topics/connectivity/usb/host.jd b/docs/html/guide/topics/connectivity/usb/host.jd
index 355dd2d..f957b60 100644
--- a/docs/html/guide/topics/connectivity/usb/host.jd
+++ b/docs/html/guide/topics/connectivity/usb/host.jd
@@ -31,7 +31,7 @@
         <li><a href="{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest</a></li>
 
         <li><a href=
-        "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher</a></li>
+        "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissileLauncher</a></li>
       </ol>
     </div>
   </div>
@@ -283,7 +283,7 @@
 
   <h3 id="permission-d">Obtaining permission to communicate with a device</h3>
 
-  <p>Before communicating with the USB device, your applicaton must have permission from your
+  <p>Before communicating with the USB device, your application must have permission from your
   users.</p>
 
   <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
@@ -388,7 +388,7 @@
   should have more logic to correctly find the correct interface and endpoints to communicate on
   and also should do any transferring of data in a different thread than the main UI thread:</p>
   <pre>
-private Byte[] bytes
+private Byte[] bytes;
 private static int TIMEOUT = 0;
 private boolean forceClaim = true;
 
@@ -409,7 +409,7 @@
   <p>For more information, see the <a href=
   "{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest sample</a>, which shows how to do
   asynchronous bulk transfers, and the <a href=
-  "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher sample</a>, which
+  "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissileLauncher sample</a>, which
   shows how to listen on an interrupt endpoint asynchronously.</p>
 
   <h3 id="terminating-d">Terminating communication with a device</h3>
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index ecba508..77f16dd 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -24,7 +24,7 @@
 attributes for each of its parts:
 
 <p style="margin-left: 2em">
-{@code &lt;scheme>://&lt;host>:&lt;port>/[&lt;path>|&lt;pathPrefix>|&lt;pathPattern>]}</p>
+{@code &lt;scheme>://&lt;host>:&lt;port>[&lt;path>|&lt;pathPrefix>|&lt;pathPattern>]}</p>
 
 <p>
 These attributes that specify the URL format are optional, but also mutually dependent:
@@ -115,7 +115,8 @@
 <dt><a name="path"></a>{@code android:path}
 <br/>{@code android:pathPrefix}
 <br/>{@code android:pathPattern}</dt>
-<dd>The path part of a URI.  The {@code path} attribute specifies a complete
+<dd>The path part of a URI which must begin with a /.
+The {@code path} attribute specifies a complete
 path that is matched against the complete path in an Intent object.  The
 {@code pathPrefix} attribute specifies a partial path that is matched against
 only the initial part of the path in the Intent object.  The {@code pathPattern}
diff --git a/docs/html/images/training/geofence.png b/docs/html/images/training/geofence.png
new file mode 100644
index 0000000..2d5d3aa
--- /dev/null
+++ b/docs/html/images/training/geofence.png
Binary files differ
diff --git a/docs/html/images/training/geofence@2x.png b/docs/html/images/training/geofence@2x.png
new file mode 100644
index 0000000..2f83105
--- /dev/null
+++ b/docs/html/images/training/geofence@2x.png
Binary files differ
diff --git a/docs/html/tools/adk/adk.jd b/docs/html/tools/adk/adk.jd
index 7e75c11..3f45c3c 100644
--- a/docs/html/tools/adk/adk.jd
+++ b/docs/html/tools/adk/adk.jd
@@ -331,7 +331,7 @@
     <li>Install the application to your device.</li>
 
     <li>Connect the ADK board (USB-A) to your Android-powered device (micro-USB). Ensure that the
-    power cable to the accessory is plugged in or that the micro-USB port on the accesory is
+    power cable to the accessory is plugged in or that the micro-USB port on the accessory is
     connected to your computer for power (this also allows you to <a href="#monitoring">monitor the
     ADK board</a>). When connected, accept the prompt that asks for whether or not to open the
     DemoKit application to connect to the accessory. If the prompt does not show up, connect and
diff --git a/docs/html/tools/revisions/gradle-plugin.jd b/docs/html/tools/revisions/gradle-plugin.jd
index e083792..fd294d2 100644
--- a/docs/html/tools/revisions/gradle-plugin.jd
+++ b/docs/html/tools/revisions/gradle-plugin.jd
@@ -39,6 +39,36 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Plugin for Gradle, Revision 1.1.3</a> <em>(March 2015)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+
+    <dd>
+      <ul>
+        <li>Gradle 2.2.1 or higher.</li>
+        <li>Build Tools 21.1.1 or higher.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+    <ul>
+      <li>Fixed issue with duplicated dependencies on a test app that triggered a ProGuard failure. </li>
+      <li>Fixed Comparator implementation which did not comply with the JDK Comparator contract and
+      generated a JDK 7 error.</li>
+    </ul>
+    </dd>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Plugin for Gradle, Revision 1.1.2</a> <em>(February 2015)</em>
   </p>
 
@@ -68,7 +98,6 @@
 
 
 
-
 <div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index b5a6477..47b603a 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -24,7 +24,7 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
-      alt=""/>SDK Tools, Revision 24.1.2</a> <em>(February 2014)</em>
+      alt=""/>SDK Tools, Revision 24.1.2</a> <em>(February 2015)</em>
   </p>
 
   <div class="toggle-content-toggleme">
diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd
index 748b6ec..59fc4c6 100644
--- a/docs/html/training/location/geofencing.jd
+++ b/docs/html/training/location/geofencing.jd
@@ -9,9 +9,11 @@
 
 <h2>This lesson teaches you to</h2>
 <ol>
-    <li><a href="#RequestGeofences">Request Geofence Monitoring</a></li>
+    <li><a href="#RequestGeofences">Set up for Geofence Monitoring</a></li>
+    <li><a href="#CreateAdd">Create and Add Geofences</a></li>
     <li><a href="#HandleGeofenceTransitions">Handle Geofence Transitions</a></li>
     <li><a href="#StopGeofenceMonitoring">Stop Geofence Monitoring</a></li>
+
 </ol>
 
 <h2>You should also read</h2>
@@ -23,577 +25,148 @@
 
 <h2>Try it out</h2>
 
-<div class="download-box">
-  <a href="http://developer.android.com/shareables/training/GeofenceDetection.zip" class="button">Download the sample</a>
-  <p class="filename">GeofenceDetection.zip</p>
-</div>
+   <ul>
+      <li>
+        <a href="https://github.com/googlesamples/android-play-location/tree/master/Geofencing"
+        class="external-link">Geofencing</a>
+      </li>
+    </ul>
 
 </div>
 </div>
 <p>
-    Geofencing combines awareness of the user's current location with awareness of nearby
-    features, defined as the user's proximity to locations that may be of interest. To mark a
+    Geofencing combines awareness of the user's current location with awareness of the user's
+    proximity to locations that may be of interest. To mark a
     location of interest, you specify its latitude and longitude. To adjust the proximity for the
-    location, you add a radius. The latitude, longitude, and radius define a geofence.
-    You can have multiple active geofences at one time.
+    location, you add a radius. The latitude, longitude, and radius define a geofence, creating a
+    circular area, or fence, around the location of interest.
 </p>
 <p>
-    Location Services treats a geofences as an area rather than as a points and proximity. This
-    allows it to detect when the user enters or exits a geofence. For each geofence, you can ask
-    Location Services to send you entrance events or exit events or both. You can also limit the
-    duration of a geofence by specifying an expiration duration in milliseconds. After the geofence
-    expires, Location Services automatically removes it.
+    You can have multiple active geofences, with a limit of 100 per device user. For each geofence,
+    you can ask Location Services to send you entrance and exit events, or you can specify a
+    duration within the geofence area to wait, or <em>dwell</em>, before triggering an event. You
+    can limit the duration of any geofence by specifying an expiration duration in milliseconds.
+    After the geofence expires, Location Services automatically removes it.
 </p>
-<!--
-    Send geofences to Location Services
- -->
-<h2 id="RequestGeofences">Request Geofence Monitoring</h2>
+
+<img src="{@docRoot}images/training/geofence@2x.png"
+srcset="{@docRoot}images/training/geofence.png 1x, {@docRoot}images/training/geofence@2x.png 2x" alt=""
+  width="400" height="400"/>
+<p>
+    This lesson shows you how to add and remove geofences, and then listen for geofence transitions
+    using an {@link android.app.IntentService}.</p>
+
+<h2 id="RequestGeofences">Set up for Geofence Monitoring</h2>
 <p>
     The first step in requesting geofence monitoring is to request the necessary permission.
     To use geofencing, your app must request
     {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. To request this
     permission, add the following element as a child element of the
 <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
-    element:
+    element in your app manifest:
 </p>
 <pre>
 &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/&gt;
 </pre>
-<!-- Check for Google Play services -->
-<h3>Check for Google Play Services</h3>
-<p>
-    Location Services is part of the Google Play services APK. Since it's hard to anticipate the
-    state of the user's device, you should always check that the APK is installed before you attempt
-    to connect to Location Services. To check that the APK is installed, call
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>,
-    which returns one of the
-    integer result codes listed in the API reference documentation. If you encounter an error,
-    call
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code>
-    to retrieve localized dialog that prompts users to take the correct action, then display
-    the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the
-    user to correct the problem, in which case Google Play services may send a result back to your
-    activity. To handle this result, override the method
-    {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()}
 
-</p>
-<p class="note">
-    <strong>Note:</strong> To make your app compatible with
-    platform version 1.6 and later, the activity that displays the
-    {@link android.support.v4.app.DialogFragment} must subclass
-    {@link android.support.v4.app.FragmentActivity} instead of {@link android.app.Activity}. Using
-    {@link android.support.v4.app.FragmentActivity} also allows you to call
-    {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager
-    getSupportFragmentManager()} to display the {@link android.support.v4.app.DialogFragment}.
-</p>
 <p>
-    Since you usually need to check for Google Play services in more than one place in your code,
-    define a method that encapsulates the check, then call the method before each connection
-    attempt. The following snippet contains all of the code required to check for Google
-    Play services:
+    If you want to use an {@link android.app.IntentService} to listen for geofence transitions,
+    add an element specifying the service name. This element must be
+    a child of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">
+    &lt;application&gt;</a></code> element:
+</p>
+
+<pre>
+&lt;application
+   android:allowBackup=&quot;true&quot;&gt;
+   ...
+   &lt;service android:name=".GeofenceTransitionsIntentService"/&gt;
+&lt;application/&gt;
+</pre>
+
+<p>To access the location APIs, you need to create an instance of the
+  Google Play services API client. To learn how to connect your client, see
+  <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect
+  to Google Play Services</a>.</p>
+
+<h2 id="CreateAdd">Create and Add Geofences</h2>
+
+<p>Your app needs to create and add geofences using the location API's builder class for
+ creating Geofence objects, and the convenience class for adding them. Also, to handle the
+ intents sent from Location Services when geofence transitions occur, you can define a
+ {@link android.app.PendingIntent} as shown in this section.
+</p>
+
+<h3>Create geofence objects</h3>
+
+<p>
+    First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.
+    html">Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and
+    transition types for the geofence. For example, to populate a list object named
+    {@code mGeofenceList}:
+    </p>
+
+<pre>
+mGeofenceList.add(new Geofence.Builder()
+    // Set the request ID of the geofence. This is a string to identify this
+    // geofence.
+    .setRequestId(entry.getKey())
+
+    .setCircularRegion(
+            entry.getValue().latitude,
+            entry.getValue().longitude,
+            Constants.GEOFENCE_RADIUS_IN_METERS
+    )
+    .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
+    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
+            Geofence.GEOFENCE_TRANSITION_EXIT)
+    .build());
+</pre>
+
+<p>This example pulls data from a constants file. In actual practice, apps might
+    dynamically create geofences based on the user's location.</p>
+
+<h3>Specify geofences and initial triggers</h3>
+
+<p>
+    The following snippet uses the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html">
+    GeofencingRequest</a></code> class
+    and its nested <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.Builder.html">
+    GeofencingRequestBuilder</a></code> class to
+    specify the geofences to monitor and to set how related geofence events are triggered:
 </p>
 <pre>
-public class MainActivity extends FragmentActivity {
-    ...
-    // Global constants
-    /*
-     * Define a request code to send to Google Play services
-     * This code is returned in Activity.onActivityResult
-     */
-    private final static int
-            CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
-    ...
-    // Define a DialogFragment that displays the error dialog
-    public static class ErrorDialogFragment extends DialogFragment {
-        // Global field to contain the error dialog
-        private Dialog mDialog;
-        ...
-        // Default constructor. Sets the dialog field to null
-        public ErrorDialogFragment() {
-            super();
-            mDialog = null;
-        }
-        ...
-        // Set the dialog to display
-        public void setDialog(Dialog dialog) {
-            mDialog = dialog;
-        }
-        ...
-        // Return a Dialog to the DialogFragment.
-        &#64;Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            return mDialog;
-        }
-        ...
-    }
-    ...
-    /*
-     * Handle results returned to the FragmentActivity
-     * by Google Play services
-     */
-     &#64;Override
-    protected void onActivityResult(
-            int requestCode, int resultCode, Intent data) {
-        // Decide what to do based on the original request code
-        switch (requestCode) {
-            ...
-            case CONNECTION_FAILURE_RESOLUTION_REQUEST :
-            /*
-             * If the result code is Activity.RESULT_OK, try
-             * to connect again
-             */
-                switch (resultCode) {
-                    ...
-                    case Activity.RESULT_OK :
-                    /*
-                     * Try the request again
-                     */
-                    ...
-                    break;
-                }
-            ...
-        }
-        ...
-    }
-    ...
-    private boolean servicesConnected() {
-        // Check that Google Play services is available
-        int resultCode =
-                GooglePlayServicesUtil.
-                        isGooglePlayServicesAvailable(this);
-        // If Google Play services is available
-        if (ConnectionResult.SUCCESS == resultCode) {
-            // In debug mode, log the status
-            Log.d("Geofence Detection",
-                    "Google Play services is available.");
-            // Continue
-            return true;
-        // Google Play services was not available for some reason
-        } else {
-            // Get the error code
-            int errorCode = connectionResult.getErrorCode();
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    errorCode,
-                    this,
-                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
-
-            // If Google Play services can provide an error dialog
-            if (errorDialog != null) {
-                // Create a new DialogFragment for the error dialog
-                ErrorDialogFragment errorFragment =
-                        new ErrorDialogFragment();
-                // Set the dialog in the DialogFragment
-                errorFragment.setDialog(errorDialog);
-                // Show the error dialog in the DialogFragment
-                errorFragment.show(
-                        getSupportFragmentManager(),
-                        "Geofence Detection");
-            }
-        }
-    }
-    ...
+private GeofencingRequest getGeofencingRequest() {
+    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
+    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
+    builder.addGeofences(mGeofenceList);
+    return builder.build();
 }
 </pre>
-<p>
-    Snippets in the following sections call this method to verify that Google Play services is
-    available.
-</p>
-<p>
-    To use geofencing, start by defining the geofences you want to monitor. Although you usually
-    store geofence data in a local database or download it from the network, you need to send
-    a geofence to Location Services as an instance of
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>,
-    which you create with
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html">Geofence.Builder</a></code>.
-    Each
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    object contains the following information:
-</p>
-<dl>
-    <dt>Latitude, longitude, and radius</dt>
-    <dd>
-        Define a circular area for the geofence. Use the latitude and longitude to mark a location
-        of interest, and then use the radius to adjust how close the user needs to approach the
-        location before the geofence is detected. The larger the radius, the more likely the
-        user will trigger a geofence transition alert by approaching the geofence. For example,
-        providing a large radius for a geofencing app that turns on lights in the user's house as
-        the user returns home might cause the lights to go on even if the user is simply passing by.
-    </dd>
-    <dt>Expiration time</dt>
-    <dd>
-        How long the geofence should remain active. Once the expiration time is reached, Location
-        Services deletes the geofence. Most of the time, you should specify an expiration time, but
-        you may want to keep permanent geofences for the user's home or place of work.
-    </dd>
-    <dt>Transition type</dt>
-    <dd>
-        Location Services can detect when the user steps within the radius of the geofence ("entry")
-        and when the user steps outside the radius of the geofence ("exit"), or both.
-    </dd>
-    <dt>Geofence ID</dt>
-    <dd>
-        A string that is stored with the geofence. You should make this unique, so that you can
-        use it to remove a geofence from Location Services tracking.
-    </dd>
-</dl>
-<h3>Define geofence storage</h3>
-<p>
-    A geofencing app needs to read and write geofence data to persistent storage. You shouldn't use
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    objects to do this; instead, use storage techniques such as databases that can store groups of
-    related data.
-</p>
-<p>
-    As an example of storing geofence data, the following snippet defines two classes that use
-    the app's {@link android.content.SharedPreferences} instance for persistent storage. The class
-    {@code SimpleGeofence}, analogous to a database record, stores the
-    data for a single
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    object in a "flattened" form. The class {@code SimpleGeofenceStore}, analogous to a database,
-    reads and writes {@code SimpleGeofence} data to the
-    {@link android.content.SharedPreferences} instance.
-</p>
-<pre>
-public class MainActivity extends FragmentActivity {
-    ...
-    /**
-     * A single Geofence object, defined by its center and radius.
-     */
-    public class SimpleGeofence {
-            // Instance variables
-            private final String mId;
-            private final double mLatitude;
-            private final double mLongitude;
-            private final float mRadius;
-            private long mExpirationDuration;
-            private int mTransitionType;
 
-        /**
-         * @param geofenceId The Geofence's request ID
-         * @param latitude Latitude of the Geofence's center.
-         * @param longitude Longitude of the Geofence's center.
-         * @param radius Radius of the geofence circle.
-         * @param expiration Geofence expiration duration
-         * @param transition Type of Geofence transition.
-         */
-        public SimpleGeofence(
-                String geofenceId,
-                double latitude,
-                double longitude,
-                float radius,
-                long expiration,
-                int transition) {
-            // Set the instance fields from the constructor
-            this.mId = geofenceId;
-            this.mLatitude = latitude;
-            this.mLongitude = longitude;
-            this.mRadius = radius;
-            this.mExpirationDuration = expiration;
-            this.mTransitionType = transition;
-        }
-        // Instance field getters
-        public String getId() {
-            return mId;
-        }
-        public double getLatitude() {
-            return mLatitude;
-        }
-        public double getLongitude() {
-            return mLongitude;
-        }
-        public float getRadius() {
-            return mRadius;
-        }
-        public long getExpirationDuration() {
-            return mExpirationDuration;
-        }
-        public int getTransitionType() {
-            return mTransitionType;
-        }
-        /**
-         * Creates a Location Services Geofence object from a
-         * SimpleGeofence.
-         *
-         * @return A Geofence object
-         */
-        public Geofence toGeofence() {
-            // Build a new Geofence object
-            return new Geofence.Builder()
-                    .setRequestId(getId())
-                    .setTransitionTypes(mTransitionType)
-                    .setCircularRegion(
-                            getLatitude(), getLongitude(), getRadius())
-                    .setExpirationDuration(mExpirationDuration)
-                    .build();
-        }
-    }
-    ...
-    /**
-     * Storage for geofence values, implemented in SharedPreferences.
-     */
-    public class SimpleGeofenceStore {
-        // Keys for flattened geofences stored in SharedPreferences
-        public static final String KEY_LATITUDE =
-                "com.example.android.geofence.KEY_LATITUDE";
-        public static final String KEY_LONGITUDE =
-                "com.example.android.geofence.KEY_LONGITUDE";
-        public static final String KEY_RADIUS =
-                "com.example.android.geofence.KEY_RADIUS";
-        public static final String KEY_EXPIRATION_DURATION =
-                "com.example.android.geofence.KEY_EXPIRATION_DURATION";
-        public static final String KEY_TRANSITION_TYPE =
-                "com.example.android.geofence.KEY_TRANSITION_TYPE";
-        // The prefix for flattened geofence keys
-        public static final String KEY_PREFIX =
-                "com.example.android.geofence.KEY";
-        /*
-         * Invalid values, used to test geofence storage when
-         * retrieving geofences
-         */
-        public static final long INVALID_LONG_VALUE = -999l;
-        public static final float INVALID_FLOAT_VALUE = -999.0f;
-        public static final int INVALID_INT_VALUE = -999;
-        // The SharedPreferences object in which geofences are stored
-        private final SharedPreferences mPrefs;
-        // The name of the SharedPreferences
-        private static final String SHARED_PREFERENCES =
-                "SharedPreferences";
-        // Create the SharedPreferences storage with private access only
-        public SimpleGeofenceStore(Context context) {
-            mPrefs =
-                    context.getSharedPreferences(
-                            SHARED_PREFERENCES,
-                            Context.MODE_PRIVATE);
-        }
-        /**
-         * Returns a stored geofence by its id, or returns {@code null}
-         * if it's not found.
-         *
-         * @param id The ID of a stored geofence
-         * @return A geofence defined by its center and radius. See
-         */
-        public SimpleGeofence getGeofence(String id) {
-            /*
-             * Get the latitude for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            double lat = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_LATITUDE),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the longitude for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            double lng = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_LONGITUDE),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the radius for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            float radius = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_RADIUS),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the expiration duration for the geofence identified
-             * by id, or INVALID_LONG_VALUE if it doesn't exist
-             */
-            long expirationDuration = mPrefs.getLong(
-                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),
-                    INVALID_LONG_VALUE);
-            /*
-             * Get the transition type for the geofence identified by
-             * id, or INVALID_INT_VALUE if it doesn't exist
-             */
-            int transitionType = mPrefs.getInt(
-                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),
-                    INVALID_INT_VALUE);
-            // If none of the values is incorrect, return the object
-            if (
-                lat != GeofenceUtils.INVALID_FLOAT_VALUE &amp;&amp;
-                lng != GeofenceUtils.INVALID_FLOAT_VALUE &amp;&amp;
-                radius != GeofenceUtils.INVALID_FLOAT_VALUE &amp;&amp;
-                expirationDuration !=
-                        GeofenceUtils.INVALID_LONG_VALUE &amp;&amp;
-                transitionType != GeofenceUtils.INVALID_INT_VALUE) {
-
-                // Return a true Geofence object
-                return new SimpleGeofence(
-                        id, lat, lng, radius, expirationDuration,
-                        transitionType);
-            // Otherwise, return null.
-            } else {
-                return null;
-            }
-        }
-        /**
-         * Save a geofence.
-         * @param geofence The SimpleGeofence containing the
-         * values you want to save in SharedPreferences
-         */
-        public void setGeofence(String id, SimpleGeofence geofence) {
-            /*
-             * Get a SharedPreferences editor instance. Among other
-             * things, SharedPreferences ensures that updates are atomic
-             * and non-concurrent
-             */
-            Editor editor = mPrefs.edit();
-            // Write the Geofence values to SharedPreferences
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_LATITUDE),
-                    (float) geofence.getLatitude());
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_LONGITUDE),
-                    (float) geofence.getLongitude());
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_RADIUS),
-                    geofence.getRadius());
-            editor.putLong(
-                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),
-                    geofence.getExpirationDuration());
-            editor.putInt(
-                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),
-                    geofence.getTransitionType());
-            // Commit the changes
-            editor.commit();
-        }
-        public void clearGeofence(String id) {
-            /*
-             * Remove a flattened geofence object from storage by
-             * removing all of its keys
-             */
-            Editor editor = mPrefs.edit();
-            editor.remove(getGeofenceFieldKey(id, KEY_LATITUDE));
-            editor.remove(getGeofenceFieldKey(id, KEY_LONGITUDE));
-            editor.remove(getGeofenceFieldKey(id, KEY_RADIUS));
-            editor.remove(getGeofenceFieldKey(id,
-                    KEY_EXPIRATION_DURATION));
-            editor.remove(getGeofenceFieldKey(id, KEY_TRANSITION_TYPE));
-            editor.commit();
-        }
-        /**
-         * Given a Geofence object's ID and the name of a field
-         * (for example, KEY_LATITUDE), return the key name of the
-         * object's values in SharedPreferences.
-         *
-         * @param id The ID of a Geofence object
-         * @param fieldName The field represented by the key
-         * @return The full key name of a value in SharedPreferences
-         */
-        private String getGeofenceFieldKey(String id,
-                String fieldName) {
-            return KEY_PREFIX + "_" + id + "_" + fieldName;
-        }
-    }
-    ...
-}
-</pre>
-<h3>Create Geofence objects</h3>
 <p>
-    The following snippet uses the {@code SimpleGeofence} and {@code SimpleGeofenceStore} classes
-    gets geofence data from the UI, stores it in {@code SimpleGeofence} objects, stores these
-    objects in a {@code SimpleGeofenceStore} object, and then creates
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    objects:
+    This example shows the use of two geofence triggers. The <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+    GEOFENCE_TRANSITION_ENTER</a></code>
+    transition triggers when a device enters a geofence, and the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">
+    GEOFENCE_TRANSITION_EXIT</a></code>
+    transition triggers when a device exits a geofence. Specifying
+    <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_ENTER">
+        INITIAL_TRIGGER_ENTER</a></code> tells Location services that
+    <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+        GEOFENCE_TRANSITION_ENTER</a></code>
+    should be triggered if the the device is already inside the geofence.</p>
 </p>
-<pre>
-public class MainActivity extends FragmentActivity {
-    ...
-    /*
-     * Use to set an expiration time for a geofence. After this amount
-     * of time Location Services will stop tracking the geofence.
-     */
-    private static final long SECONDS_PER_HOUR = 60;
-    private static final long MILLISECONDS_PER_SECOND = 1000;
-    private static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;
-    private static final long GEOFENCE_EXPIRATION_TIME =
-            GEOFENCE_EXPIRATION_IN_HOURS *
-            SECONDS_PER_HOUR *
-            MILLISECONDS_PER_SECOND;
-    ...
-    /*
-     * Handles to UI views containing geofence data
-     */
-    // Handle to geofence 1 latitude in the UI
-    private EditText mLatitude1;
-    // Handle to geofence 1 longitude in the UI
-    private EditText mLongitude1;
-    // Handle to geofence 1 radius in the UI
-    private EditText mRadius1;
-    // Handle to geofence 2 latitude in the UI
-    private EditText mLatitude2;
-    // Handle to geofence 2 longitude in the UI
-    private EditText mLongitude2;
-    // Handle to geofence 2 radius in the UI
-    private EditText mRadius2;
-    /*
-     * Internal geofence objects for geofence 1 and 2
-     */
-    private SimpleGeofence mUIGeofence1;
-    private SimpleGeofence mUIGeofence2;
-    ...
-    // Internal List of Geofence objects
-    List&lt;Geofence&gt; mGeofenceList;
-    // Persistent storage for geofences
-    private SimpleGeofenceStore mGeofenceStorage;
-    ...
-    &#64;Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        ...
-        // Instantiate a new geofence storage area
-        mGeofenceStorage = new SimpleGeofenceStore(this);
 
-        // Instantiate the current List of geofences
-        mCurrentGeofences = new ArrayList&lt;Geofence&gt;();
-    }
-    ...
-    /**
-     * Get the geofence parameters for each geofence from the UI
-     * and add them to a List.
-     */
-    public void createGeofences() {
-        /*
-         * Create an internal object to store the data. Set its
-         * ID to "1". This is a "flattened" object that contains
-         * a set of strings
-         */
-        mUIGeofence1 = new SimpleGeofence(
-                "1",
-                Double.valueOf(mLatitude1.getText().toString()),
-                Double.valueOf(mLongitude1.getText().toString()),
-                Float.valueOf(mRadius1.getText().toString()),
-                GEOFENCE_EXPIRATION_TIME,
-                // This geofence records only entry transitions
-                Geofence.GEOFENCE_TRANSITION_ENTER);
-        // Store this flat version
-        mGeofenceStorage.setGeofence("1", mUIGeofence1);
-        // Create another internal object. Set its ID to "2"
-        mUIGeofence2 = new SimpleGeofence(
-                "2",
-                Double.valueOf(mLatitude2.getText().toString()),
-                Double.valueOf(mLongitude2.getText().toString()),
-                Float.valueOf(mRadius2.getText().toString()),
-                GEOFENCE_EXPIRATION_TIME,
-                // This geofence records both entry and exit transitions
-                Geofence.GEOFENCE_TRANSITION_ENTER |
-                Geofence.GEOFENCE_TRANSITION_EXIT);
-        // Store this flat version
-        mGeofenceStorage.setGeofence(2, mUIGeofence2);
-        mGeofenceList.add(mUIGeofence1.toGeofence());
-        mGeofenceList.add(mUIGeofence2.toGeofence());
-    }
-    ...
-}
-</pre>
-<p>
-    In addition to the {@link java.util.List} of
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    objects you want to monitor, you need to provide Location Services with the
-    {@link android.content.Intent} that it sends to your app when it detects geofence
-    transitions.
-<h4>Define a Intent for geofence transitions</h4>
+<p>In many cases, it may be preferable to use instead <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_DWELL">
+    INITIAL_TRIGGER_DWELL</a></code>,
+    which triggers events only when the user stops for a defined duration within a geofence.
+    This approach can help reduce "alert spam" resulting from large numbers notifications when a
+    device briefly enters and exits geofences. Another strategy for getting best results from your
+    geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy
+    of typical WiFi networks, and also helps reduce device power consumption.
+</p>
+
+<h3>Define an Intent for geofence transitions</h3>
 <p>
     The {@link android.content.Intent} sent from Location Services can trigger various actions in
     your app, but you should <i>not</i> have it start an activity or fragment, because components
@@ -601,807 +174,133 @@
     {@link android.app.IntentService} is a good way to handle the intent. An
     {@link android.app.IntentService} can post a notification, do long-running background work,
     send intents to other services, or send a broadcast intent. The following snippet shows how
-    how to define a {@link android.app.PendingIntent} that starts an
-    {@link android.app.IntentService}:
+    to define a {@link android.app.PendingIntent} that starts an {@link android.app.IntentService}:
 </p>
 <pre>
 public class MainActivity extends FragmentActivity {
     ...
-    /*
-     * Create a PendingIntent that triggers an IntentService in your
-     * app when a geofence transition occurs.
-     */
-    private PendingIntent getTransitionPendingIntent() {
-        // Create an explicit Intent
-        Intent intent = new Intent(this,
-                ReceiveTransitionsIntentService.class);
-        /*
-         * Return the PendingIntent
-         */
-        return PendingIntent.getService(
-                this,
-                0,
-                intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-    }
-    ...
-}
-</pre>
-<p>
-    Now you have all the code you need to send a request to monitor geofences to Location
-    Services.
-</p>
-<!-- Send the monitoring request -->
-<h3 id="requestmonitoring">Send the monitoring request</h3>
-<p>
-    Sending the monitoring request requires two asynchronous operations. The first operation gets a
-    location client for the request, and the second makes the request using the client. In both
-    cases, Location Services invokes a callback method when it finishes the operation. The best way
-    to handle these operations is to chain together the method calls. The following snippets
-    demonstrate how to set up an activity, define the methods, and call them in the proper order.
-</p>
-<p>
-     First, modify the activity's class definition to implement the necessary callback interfaces.
-     Add the following interfaces:
-</p>
-<dl>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code>
-    </dt>
-    <dd>
-        Specifies methods that Location Services calls when a location client is connected or
-        disconnected.
-    </dd>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code>
-    </dt>
-    <dd>
-        Specifies a method that Location Services calls if an error occurs while attempting to
-        connect the location client.
-    </dd>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html">OnAddGeofencesResultListener</a></code>
-    </dt>
-    <dd>
-        Specifies a method that Location Services calls once it has added the geofences.
-    </dd>
-</dl>
-<p>
-    For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-}
-</pre>
-<h4>Start the request process</h4>
-<p>
-    Next, define a method that starts the request process by connecting to Location Services.
-    Mark this as a request to add a geofence by setting a global variable. This allows you to
-    use the callback
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code>
-    to add geofences and to remove them, as described in succeeding sections.
-</p>
-<p>
-<p>
-    To guard against race conditions that might arise if your app tries to start another request
-    before the first one finishes, define a boolean flag that tracks the state of the current
-    request:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Holds the location client
-    private LocationClient mLocationClient;
-    // Stores the PendingIntent used to request geofence monitoring
-    private PendingIntent mGeofenceRequestIntent;
-    // Defines the allowable request types.
-    public enum REQUEST_TYPE = {ADD}
-    private REQUEST_TYPE mRequestType;
-    // Flag that indicates if a request is underway.
-    private boolean mInProgress;
-    ...
-    &#64;Override
-    protected void onCreate(Bundle savedInstanceState) {
-        ...
-        // Start with the request flag set to false
-        mInProgress = false;
-        ...
-    }
-    ...
-    /**
-     * Start a request for geofence monitoring by calling
-     * LocationClient.connect().
-     */
-    public void addGeofences() {
-        // Start a request to add geofences
-        mRequestType = ADD;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the proper request
-         * can be restarted.
-         */
-        if (!servicesConnected()) {
-            return;
+    private PendingIntent getGeofencePendingIntent() {
+        // Reuse the PendingIntent if we already have it.
+        if (mGeofencePendingIntent != null) {
+            return mGeofencePendingIntent;
         }
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this)
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
+        Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
+        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
+        // calling addGeofences() and removeGeofences().
+        return PendingIntent.getService(this, 0, intent, PendingIntent.
+                FLAG_UPDATE_CURRENT);
     }
-    ...
-}
 </pre>
-<h4>Send a request to add the geofences</h4>
+
+<h3>Add geofences</h3>
+
 <p>
-    In your implementation of
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code>,
-    call
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">LocationClient.addGeofences()</a></code>.
-    Notice that if the connection fails,
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code>
-    isn't called, and the request stops.
+    To add geofences, use the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html#addGeofences(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.GeofencingRequest, android.app.PendingIntent)">{@code GeoencingApi.addGeofences()}</a></code> method.
+    Provide the Google API client, the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest">
+    GeofencingRequest</a></code> object, and the {@link android.app.PendingIntent}.
+    The following snippet, which processes the results in <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)">
+    onResult()</a></code>, assumes that the main activity implements <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html">
+    ResultCallback</a></code>:
 </p>
 <pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
+public class MainActivity extends FragmentActivity {
     ...
-    /*
-     * Provide the implementation of ConnectionCallbacks.onConnected()
-     * Once the connection is available, send a request to add the
-     * Geofences
-     */
-    &#64;Override
-    private void onConnected(Bundle dataBundle) {
-        ...
-        switch (mRequestType) {
-            case ADD :
-                // Get the PendingIntent for the request
-                mTransitionPendingIntent =
-                        getTransitionPendingIntent();
-                // Send a request to add the current geofences
-                mLocationClient.addGeofences(
-                        mCurrentGeofences, pendingIntent, this);
-            ...
-        }
-    }
-    ...
-}
+    LocationServices.GeofencingApi.addGeofences(
+                mGoogleApiClient,
+                getGeofencingRequest(),
+                getGeofencePendingIntent()
+        ).setResultCallback(this);
 </pre>
-<p>
-    Notice that
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">addGeofences()</a></code>
-    returns immediately, but the status of the request is indeterminate until Location Services
-    calls
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult()</a></code>
-    Once this method is called, you can determine if the request was successful or not.
-</p>
-<h4>Check the result returned by Location Services</h4>
-<p>
-    When Location Services invokes your implementation of the callback method
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult()</a></code>,
-    indicating that the request is complete, examine the incoming status code. If the request
-    was successful, the geofences you requested are active. If the request was unsuccessful,
-    the geofences aren't active, and you need to re-try the request or report an error. For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-        ...
-    /*
-     * Provide the implementation of
-     * OnAddGeofencesResultListener.onAddGeofencesResult.
-     * Handle the result of adding the geofences
-     *
-     */
-    &#64;Override
-    public void onAddGeofencesResult(
-            int statusCode, String[] geofenceRequestIds) {
-        // If adding the geofences was successful
-        if (LocationStatusCodes.SUCCESS == statusCode) {
-            /*
-             * Handle successful addition of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If adding the geofences failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        // Turn off the in progress flag and disconnect the client
-        mInProgress = false;
-        mLocationClient.disconnect();
-    }
-    ...
-}
-</pre>
-<!-- Handle disconnections -->
-<h3>Handle disconnections</h3>
-<p>
-    In some cases, Location Services may disconnect from the activity recognition client before
-    you call
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#disconnect()">disconnect()</a></code>.
-    To handle this situation, implement <code>
-<a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onDisconnected()">onDisconnected()</a></code>.
-    In this method, set the request flag to indicate that a request is not in progress, and
-    delete the client:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /*
-     * Implement ConnectionCallbacks.onDisconnected()
-     * Called by Location Services once the location client is
-     * disconnected.
-     */
-    &#64;Override
-    public void onDisconnected() {
-        // Turn off the request flag
-        mInProgress = false;
-        // Destroy the current location client
-        mLocationClient = null;
-    }
-    ...
-}
-</pre>
-<!-- Handle connection errors -->
-<h3>Handle connection errors</h3>
-<p>
-    Besides handling the normal callbacks from Location Services, you have to provide a callback
-    method that Location Services calls if a connection error occurs. This callback method
-    can re-use the {@link android.support.v4.app.DialogFragment} class that you defined to
-    handle the check for Google Play services. It can also re-use the override you defined
-    for {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()} that
-    receives any Google Play services results that occur when the user interacts with the
-    error dialog. The following snippet shows you a sample implementation of the callback method:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Implementation of OnConnectionFailedListener.onConnectionFailed
-    &#64;Override
-    public void onConnectionFailed(ConnectionResult connectionResult) {
-        // Turn off the request flag
-        mInProgress = false;
-        /*
-         * If the error has a resolution, start a Google Play services
-         * activity to resolve it.
-         */
-        if (connectionResult.hasResolution()) {
-            try {
-                connectionResult.startResolutionForResult(
-                        this,
-                        CONNECTION_FAILURE_RESOLUTION_REQUEST);
-            } catch (SendIntentException e) {
-                // Log the error
-                e.printStackTrace();
-            }
-        // If no resolution is available, display an error dialog
-        } else {
-            // Get the error code
-            int errorCode = connectionResult.getErrorCode();
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    errorCode,
-                    this,
-                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
-            // If Google Play services can provide an error dialog
-            if (errorDialog != null) {
-                // Create a new DialogFragment for the error dialog
-                ErrorDialogFragment errorFragment =
-                        new ErrorDialogFragment();
-                // Set the dialog in the DialogFragment
-                errorFragment.setDialog(errorDialog);
-                // Show the error dialog in the DialogFragment
-                errorFragment.show(
-                        getSupportFragmentManager(),
-                        "Geofence Detection");
-            }
-        }
-    }
-    ...
-}
-</pre>
-<!--
-    Handle Geofence Transitions
- -->
+
+
 <h2 id="HandleGeofenceTransitions">Handle Geofence Transitions</h2>
 <p>
     When Location Services detects that the user has entered or exited a geofence, it
     sends out the {@link android.content.Intent} contained in the {@link android.app.PendingIntent}
-    you included in the request to add geofences. This {@link android.content.Intent} is
+    you included in the request to add geofences. This {@link android.content.Intent} is received
+    by a service like <code>GeofenceTransitionsIntentService</code>,
+    which obtains the geofencing event from the intent, determines the type of Geofence transition(s),
+    and determines which of the defined geofences was triggered. It then sends a notification as
+    the output.
 </p>
-<h3>Define an IntentService</h3>
 <p>
     The following snippet shows how to define an {@link android.app.IntentService} that posts a
     notification when a geofence transition occurs. When the user clicks the notification, the
     app's main activity appears:
 </p>
 <pre>
-public class ReceiveTransitionsIntentService extends IntentService {
-    ...
-    /**
-     * Sets an identifier for the service
-     */
-    public ReceiveTransitionsIntentService() {
-        super("ReceiveTransitionsIntentService");
-    }
-    /**
-     * Handles incoming intents
-     *&#64;param intent The Intent sent by Location Services. This
-     * Intent is provided
-     * to Location Services (inside a PendingIntent) when you call
-     * addGeofences()
-     */
-    &#64;Override
+public class GeofenceTransitionsIntentService extends IntentService {
+   ...
     protected void onHandleIntent(Intent intent) {
-        // First check for errors
-        if (LocationClient.hasError(intent)) {
-            // Get the error code with a static method
-            int errorCode = LocationClient.getErrorCode(intent);
-            // Log the error
-            Log.e("ReceiveTransitionsIntentService",
-                    "Location Services error: " +
-                    Integer.toString(errorCode));
-            /*
-             * You can also send the error code to an Activity or
-             * Fragment with a broadcast Intent
-             */
-        /*
-         * If there's no error, get the transition type and the IDs
-         * of the geofence or geofences that triggered the transition
-         */
-        } else {
-            // Get the type of transition (entry or exit)
-            int transitionType =
-                    LocationClient.getGeofenceTransition(intent);
-            // Test that a valid transition was reported
-            if (
-                (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER)
-                 ||
-                (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT)
-               ) {
-                List &lt;Geofence&gt; triggerList =
-                        getTriggeringGeofences(intent);
+        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
+        if (geofencingEvent.hasError()) {
+            String errorMessage = GeofenceErrorMessages.getErrorString(this,
+                    geofencingEvent.getErrorCode());
+            Log.e(TAG, errorMessage);
+            return;
+        }
 
-                String[] triggerIds = new String[geofenceList.size()];
+        // Get the transition type.
+        int geofenceTransition = geofencingEvent.getGeofenceTransition();
 
-                for (int i = 0; i &lt; triggerIds.length; i++) {
-                    // Store the Id of each geofence
-                    triggerIds[i] = triggerList.get(i).getRequestId();
-                }
-                /*
-                 * At this point, you can store the IDs for further use
-                 * display them, or display the details associated with
-                 * them.
-                 */
-            }
-        // An invalid transition was reported
+        // Test that the reported transition was of interest.
+        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
+                geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
+
+            // Get the geofences that were triggered. A single event can trigger
+            // multiple geofences.
+            List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
+
+            // Get the transition details as a String.
+            String geofenceTransitionDetails = getGeofenceTransitionDetails(
+                    this,
+                    geofenceTransition,
+                    triggeringGeofences
+            );
+
+            // Send notification and log the transition details.
+            sendNotification(geofenceTransitionDetails);
+            Log.i(TAG, geofenceTransitionDetails);
         } else {
-            Log.e("ReceiveTransitionsIntentService",
-                    "Geofence transition error: " +
-                    Integer.toString()transitionType));
+            // Log the error.
+            Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
+                    geofenceTransition));
         }
     }
-    ...
-}
 </pre>
-<!-- Specify the IntentService in the manifest -->
-<h3>Specify the IntentService in the manifest</h3>
-<p>
-    To identify the {@link android.app.IntentService} to the system, add a
-    <code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
-    element to the app manifest. For example:
-</p>
-<pre>
-&lt;service
-    android:name="com.example.android.location.ReceiveTransitionsIntentService"
-    android:label="&#64;string/app_name"
-    android:exported="false"&gt;
-&lt;/service&gt;
-</pre>
-<p>
-    Notice that you don't have to specify intent filters for the service, because it only receives
-    explicit intents. How the incoming geofence transition intents are created is described in the
-    section <a href="#requestmonitoring">Send the monitoring request</a>.
-</p>
+
+<p>After detecting the transition event via the {@link android.app.PendingIntent},
+    this {@link android.app.IntentService} gets the geofence transition type and tests whether
+    it is one of the events the app uses to trigger notifications -- either
+    <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">GEOFENCE_TRANSITION_ENTER</a></code>
+     or <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">GEOFENCE_TRANSITION_EXIT</a></code>
+    in this case. The service then sends a notification and logs the transition details.</p>
 <!--
     Remove Geofences
  -->
 <h2 id="StopGeofenceMonitoring">Stop Geofence Monitoring</h2>
-<p>
-    To stop geofence monitoring, you remove the geofences themselves. You can remove a specific
-    set of geofences or all the geofences associated with a {@link android.app.PendingIntent}. The
-    procedure is similar to adding geofences. The first operation gets a location
-    client for the removal request, and the second makes the request using the client.
+
+<p>Stopping geofence monitoring when it is no longer needed or desired can help save battery
+    power and CPU cycles on the device. You can stop geofence monitoring
+    in the main activity used to add and remove geofences; removing a geofence stops it
+    immediately. The API provides methods to
+    remove geofences either by request IDs, or by removing geofences associated with a given
+    {@link android.app.PendingIntent}.
 </p>
 <p>
-    The callback methods that Location Services invokes when it has finished removing geofences
-    are defined in the interface
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a></code>. Declare
-    this interface as part of your class definition, and then add definitions for its two methods:
-</p>
-<dl>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult()</a></code>
-    </dt>
-    <dd>
-        Callback invoked when Location Services finishes a request to remove all geofences made
-        by the method
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener)</a></code>.
-    </dd>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult(List&lt;String&gt;, LocationClient.OnRemoveGeofencesResultListener)</a></code>
-    </dt>
-    <dd>
-        Callback invoked when Location Services finished a request to remove a set of geofences,
-        specified by their geofence IDs, by the method
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(java.util.List<java.lang.String>, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(List&lt;String&gt;, LocationClient.OnRemoveGeofencesResultListener)</a></code>.
-    </dd>
-</dl>
-<p>
-    Examples of implementing these methods are shown in the next snippets.
-</p>
-<h3>Remove all geofences</h3>
-<p>
-    Since removing geofences uses some of the methods you use to add geofences, start by defining
-    another request type:
+    The following snippet removes geofences by {@link android.app.PendingIntent}, stopping all
+    further notification when the device enters or exits previously added geofences:
 </p>
 <pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Enum type for controlling the type of removal requested
-    public enum REQUEST_TYPE = {ADD, REMOVE_INTENT}
-    ...
+LocationServices.GeofencingApi.removeGeofences(
+            mGoogleApiClient,
+            // This is the same pending intent that was used in addGeofences().
+            getGeofencePendingIntent()
+    ).setResultCallback(this); // Result processed in onResult().
 }
 </pre>
+
 <p>
-    Start the removal request by getting a connection to Location Services. If the connection fails,
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code> isn't called,
-    and the request stops. The following snippet shows how to start the request:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Start a request to remove geofences by calling
-     * LocationClient.connect()
-     */
-    public void removeGeofences(PendingIntent requestIntent) {
-        // Record the type of removal request
-        mRequestType = REMOVE_INTENT;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the request can be
-         * restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        // Store the PendingIntent
-        mGeofenceRequestIntent = requestIntent;
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this);
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
-    }
-    ...
-}
-</pre>
-<p>
-   When Location Services invokes the callback method indicating that the connection is open,
-   make the request to remove all geofences. Disconnect the client after making the request.
-   For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Once the connection is available, send a request to remove the
-     * Geofences. The method signature used depends on which type of
-     * remove request was originally received.
-     */
-    private void onConnected(Bundle dataBundle) {
-        /*
-         * Choose what to do based on the request type set in
-         * removeGeofences
-         */
-        switch (mRequestType) {
-            ...
-            case REMOVE_INTENT :
-                mLocationClient.removeGeofences(
-                        mGeofenceRequestIntent, this);
-                break;
-            ...
-        }
-    }
-    ...
-}
-</pre>
-<p>
-    Although the call to
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener)</a></code>    Services calls
-    returns immediately, the result of the removal request is indeterminate until Location Services
-    calls
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult()</a></code>.
-    The following snippet shows how to define this method:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * When the request to remove geofences by PendingIntent returns,
-     * handle the result.
-     *
-     *&#64;param statusCode the code returned by Location Services
-     *&#64;param requestIntent The Intent used to request the removal.
-     */
-    &#64;Override
-    public void onRemoveGeofencesByPendingIntentResult(int statusCode,
-            PendingIntent requestIntent) {
-        // If removing the geofences was successful
-        if (statusCode == LocationStatusCodes.SUCCESS) {
-            /*
-             * Handle successful removal of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If adding the geocodes failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        /*
-         * Disconnect the location client regardless of the
-         * request status, and indicate that a request is no
-         * longer in progress
-         */
-        mInProgress = false;
-        mLocationClient.disconnect();
-    }
-    ...
-}
-</pre>
-<h3>Remove individual geofences</h3>
-<p>
-    The procedure for removing an individual geofence or set of geofences is similar to the
-    removal of all geofences. To specify the geofences you want remove, add their geofence ID
-    values to a {@link java.util.List} of String objects. Pass this {@link java.util.List} to a
-    different definition of {@code removeGeofences} with the appropriate signature. This method
-    then starts the removal process.
-</p>
-<p>
-    Start by adding a request type for removing geofences by a list, and also add a global variable
-    for storing the list of geofences:
-</p>
-<pre>
-    ...
-    // Enum type for controlling the type of removal requested
-    public enum REQUEST_TYPE = {ADD, REMOVE_INTENT, REMOVE_LIST}
-    // Store the list of geofence Ids to remove
-    String&lt;List&gt; mGeofencesToRemove;
-</pre>
-<p>
-    Next, define a list of geofences you want to remove. For example, this snippet removes the
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    defined by the geofence ID "1":
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-        List&lt;String&gt; listOfGeofences =
-                Collections.singletonList("1");
-        removeGeofences(listOfGeofences);
-    ...
-}
-</pre>
-<p>
-    The following snippet defines the {@code removeGeofences()} method:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Start a request to remove monitoring by
-     * calling LocationClient.connect()
-     *
-     */
-    public void removeGeofences(List&lt;String&gt; geofenceIds) {
-        // If Google Play services is unavailable, exit
-        // Record the type of removal request
-        mRequestType = REMOVE_LIST;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the request can be
-         * restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        // Store the list of geofences to remove
-        mGeofencesToRemove = geofenceIds;
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this);
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
-    }
-    ...
-}
-</pre>
-<p>
-   When Location Services invokes the callback method indicating that the connection is open,
-   make the request to remove the list of geofences. Disconnect the client after making the request.
-   For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    private void onConnected(Bundle dataBundle) {
-        ...
-        switch (mRequestType) {
-        ...
-        // If removeGeofencesById was called
-            case REMOVE_LIST :
-                mLocationClient.removeGeofences(
-                        mGeofencesToRemove, this);
-                break;
-        ...
-        }
-        ...
-    }
-    ...
-}
-</pre>
-<p>
-    Define an implementation of
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult()</a></code>.
-    Location Services invokes this callback method to indicate that the request to remove a list of
-    geofences is complete. In this method, examine the incoming status code and take the
-    appropriate action:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * When the request to remove geofences by IDs returns, handle the
-     * result.
-     *
-     * &#64;param statusCode The code returned by Location Services
-     * &#64;param geofenceRequestIds The IDs removed
-     */
-    &#64;Override
-    public void onRemoveGeofencesByRequestIdsResult(
-            int statusCode, String[] geofenceRequestIds) {
-        // If removing the geocodes was successful
-        if (LocationStatusCodes.SUCCESS == statusCode) {
-            /*
-             * Handle successful removal of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If removing the geofences failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        // Indicate that a request is no longer in progress
-        mInProgress = false;
-        // Disconnect the location client
-        mLocationClient.disconnect();
-    }
-    ...
-}
-</pre>
-<p>
-    You can combine geofencing with other location-aware features, such as periodic location updates
-    or activity recognition, which are described in other lessons in this class.
-</p>
-<p>
-    The next lesson,
-    <a href="activity-recognition.html">Recognizing the User's Current Activity</a>, shows you how
-    to request and receive activity updates. At regular intervals, Location Services can send you
-    information about the user's current physical activity. Based on this information, you can
-    change your app's behavior; for example, you can switch to a longer update interval if you
-    detect that the user is walking instead of driving.
+    You can combine geofencing with other location-aware features, such as periodic location updates.
+    For more information, see the other lessons in this class.
 </p>
diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd
index 35e177f..c4dec99 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -81,4 +81,10 @@
     Learn how to convert a location's latitude and longitude into an address
     (reverse geocoding).
   </dd>
+  <dt>
+    <b><a href="geofencing.html">Creating and Monitoring Geofences</a></b>
+  </dt> <dd>
+    Learn how to define one or more geographic areas as locations of interest,
+    called geofences, and detect when the user is close to or inside a geofence.
+  </dd>
 </dl>
diff --git a/docs/html/training/scheduling/index.jd b/docs/html/training/scheduling/index.jd
index 4d2db60..4239ffb 100644
--- a/docs/html/training/scheduling/index.jd
+++ b/docs/html/training/scheduling/index.jd
@@ -1,5 +1,5 @@
 page.title=Managing Device Awake State
-page.tags=
+page.tags=wakelock, AlarmManager, WakefulBroadcastReceiver
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 89e72f1..11ae1a6 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -736,6 +736,10 @@
             Displaying a Location Address
           </a>
           </li>
+          <li><a href="<?cs var:toroot ?>training/location/geofencing.html">
+            Creating and Monitoring Geofences
+          </a>
+          </li>
         </ul>
       </li>
     </ul>
diff --git a/docs/html/wear/images/partners/acer.png b/docs/html/wear/images/partners/acer.png
new file mode 100644
index 0000000..439de80
--- /dev/null
+++ b/docs/html/wear/images/partners/acer.png
Binary files differ
diff --git a/docs/html/wear/images/partners/arm.png b/docs/html/wear/images/partners/arm.png
new file mode 100644
index 0000000..3e2f642
--- /dev/null
+++ b/docs/html/wear/images/partners/arm.png
Binary files differ
diff --git a/docs/html/wear/images/partners/huawei.png b/docs/html/wear/images/partners/huawei.png
new file mode 100644
index 0000000..9099ed4
--- /dev/null
+++ b/docs/html/wear/images/partners/huawei.png
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 27e8098..316f5ca 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -202,6 +202,12 @@
 
           <div class="landing-partners cols">
             <div class="col-4">
+              <img src="/wear/images/partners/acer.png" alt="Acer">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/arm.png" alt="ARM">
+            </div>
+            <div class="col-4">
               <img src="/wear/images/partners/asus.png" alt="Asus">
             </div>
             <div class="col-4">
@@ -214,6 +220,9 @@
               <img src="/wear/images/partners/htc.png" alt="HTC">
             </div>
             <div class="col-4">
+              <img src="/wear/images/partners/huawei.png" alt="Huawei">
+            </div>
+            <div class="col-4">
               <img src="/wear/images/partners/intel.png" alt="Intel">
             </div>
             <div class="col-4">
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 132c6ef..e2f7799 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -16,11 +16,14 @@
 
 package android.graphics;
 
+import android.annotation.CheckResult;
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Trace;
 import android.util.DisplayMetrics;
+
 import dalvik.system.VMRuntime;
 
 import java.io.OutputStream;
@@ -37,21 +40,14 @@
      * @see Bitmap#setDensity(int)
      */
     public static final int DENSITY_NONE = 0;
-    
-    /**
-     * Note:  mNativeBitmap is used by FaceDetector_jni.cpp
-     * Don't change/rename without updating FaceDetector_jni.cpp
-     * 
-     * @hide
-     */
-    public final long mNativeBitmap;
+
+    private final long mSkBitmapPtr;
 
     /**
      * Backing buffer for the Bitmap.
      */
     private byte[] mBuffer;
 
-    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
     private final BitmapFinalizer mFinalizer;
 
     private final boolean mIsMutable;
@@ -92,11 +88,11 @@
         sDefaultDensity = density;
     }
 
+    @SuppressWarnings("deprecation")
     static int getDefaultDensity() {
         if (sDefaultDensity >= 0) {
             return sDefaultDensity;
         }
-        //noinspection deprecation
         sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
         return sDefaultDensity;
     }
@@ -105,7 +101,7 @@
      * Private constructor that must received an already allocated native bitmap
      * int (pointer).
      */
-    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+    // called from JNI
     Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
             boolean isMutable, boolean requestPremultiplied,
             byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
@@ -120,7 +116,7 @@
         mBuffer = buffer;
 
         // we delete this in our finalizer
-        mNativeBitmap = nativeBitmap;
+        mSkBitmapPtr = nativeBitmap;
 
         mNinePatchChunk = ninePatchChunk;
         mNinePatchInsets = ninePatchInsets;
@@ -136,7 +132,7 @@
      * Native bitmap has been reconfigured, so set premult and cached
      * width/height values
      */
-    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+    // called from JNI
     void reinit(int width, int height, boolean requestPremultiplied) {
         mWidth = width;
         mHeight = height;
@@ -227,7 +223,7 @@
             throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
         }
 
-        nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
+        nativeReconfigure(mSkBitmapPtr, width, height, config.nativeInt, mBuffer.length,
                 mRequestPremultiplied);
         mWidth = width;
         mHeight = height;
@@ -305,7 +301,7 @@
      */
     public void recycle() {
         if (!mRecycled && mFinalizer.mNativeBitmap != 0) {
-            if (nativeRecycle(mNativeBitmap)) {
+            if (nativeRecycle(mSkBitmapPtr)) {
                 // return value indicates whether native pixel object was actually recycled.
                 // false indicates that it is still in use at the native level and these
                 // objects should not be collected now. They will be collected later when the
@@ -331,13 +327,13 @@
      * Returns the generation ID of this bitmap. The generation ID changes
      * whenever the bitmap is modified. This can be used as an efficient way to
      * check if a bitmap has changed.
-     * 
+     *
      * @return The current generation ID for this bitmap.
      */
     public int getGenerationId() {
-        return nativeGenerationId(mNativeBitmap);
+        return nativeGenerationId(mSkBitmapPtr);
     }
-    
+
     /**
      * This is called by methods that want to throw an exception if the bitmap
      * has already been recycled.
@@ -399,12 +395,12 @@
          * encoded: red is stored with 5 bits of precision (32 possible
          * values), green is stored with 6 bits of precision (64 possible
          * values) and blue is stored with 5 bits of precision.
-         * 
+         *
          * This configuration can produce slight visual artifacts depending
          * on the configuration of the source. For instance, without
          * dithering, the result might show a greenish tint. To get better
          * results dithering should be applied.
-         * 
+         *
          * This configuration may be useful when using opaque bitmaps
          * that do not require high color fidelity.
          */
@@ -414,18 +410,18 @@
          * Each pixel is stored on 2 bytes. The three RGB color channels
          * and the alpha channel (translucency) are stored with a 4 bits
          * precision (16 possible values.)
-         * 
+         *
          * This configuration is mostly useful if the application needs
          * to store translucency information but also needs to save
          * memory.
-         * 
+         *
          * It is recommended to use {@link #ARGB_8888} instead of this
          * configuration.
          *
          * Note: as of {@link android.os.Build.VERSION_CODES#KITKAT},
          * any bitmap created with this configuration will be created
          * using {@link #ARGB_8888} instead.
-         * 
+         *
          * @deprecated Because of the poor quality of this configuration,
          *             it is advised to use {@link #ARGB_8888} instead.
          */
@@ -436,7 +432,7 @@
          * Each pixel is stored on 4 bytes. Each channel (RGB and alpha
          * for translucency) is stored with 8 bits of precision (256
          * possible values.)
-         * 
+         *
          * This configuration is very flexible and offers the best
          * quality. It should be used whenever possible.
          */
@@ -444,11 +440,10 @@
 
         final int nativeInt;
 
-        @SuppressWarnings({"deprecation"})
         private static Config sConfigs[] = {
             null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
         };
-        
+
         Config(int ni) {
             this.nativeInt = ni;
         }
@@ -492,7 +487,7 @@
             throw new RuntimeException("Buffer not large enough for pixels");
         }
 
-        nativeCopyPixelsToBuffer(mNativeBitmap, dst);
+        nativeCopyPixelsToBuffer(mSkBitmapPtr, dst);
 
         // now update the buffer's position
         int position = dst.position();
@@ -532,7 +527,7 @@
             throw new RuntimeException("Buffer not large enough for pixels");
         }
 
-        nativeCopyPixelsFromBuffer(mNativeBitmap, src);
+        nativeCopyPixelsFromBuffer(mSkBitmapPtr, src);
 
         // now update the buffer's position
         int position = src.position();
@@ -554,7 +549,7 @@
      */
     public Bitmap copy(Config config, boolean isMutable) {
         checkRecycled("Can't copy a recycled bitmap");
-        Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
+        Bitmap b = nativeCopy(mSkBitmapPtr, config.nativeInt, isMutable);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
             b.mDensity = mDensity;
@@ -564,7 +559,7 @@
 
     /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
-     * specified width and height are the same as the current width and height of 
+     * specified width and height are the same as the current width and height of
      * the source bitmap, the source bitmap is returned and no new bitmap is
      * created.
      *
@@ -639,7 +634,7 @@
      * transformed by the optional matrix. The new bitmap may be the
      * same object as source, or a copy may have been made. It is
      * initialized with the same density as the original bitmap.
-     * 
+     *
      * If the source bitmap is immutable and the requested subset is the
      * same as the source bitmap itself, then the source bitmap is
      * returned and no new bitmap is created.
@@ -781,8 +776,8 @@
      * @param config   The bitmap config to create.
      * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
      *                 bitmap as opaque. Doing so will clear the bitmap in black
-     *                 instead of transparent.  
-     * 
+     *                 instead of transparent.
+     *
      * @throws IllegalArgumentException if the width or height are <= 0
      */
     private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
@@ -800,8 +795,8 @@
      * @param config   The bitmap config to create.
      * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
      *                 bitmap as opaque. Doing so will clear the bitmap in black
-     *                 instead of transparent.  
-     * 
+     *                 instead of transparent.
+     *
      * @throws IllegalArgumentException if the width or height are <= 0
      */
     private static Bitmap createBitmap(DisplayMetrics display, int width, int height,
@@ -815,7 +810,7 @@
         }
         bm.setHasAlpha(hasAlpha);
         if (config == Config.ARGB_8888 && !hasAlpha) {
-            nativeErase(bm.mNativeBitmap, 0xff000000);
+            nativeErase(bm.mSkBitmapPtr, 0xff000000);
         }
         // No need to initialize the bitmap to zeroes with other configs;
         // it is backed by a VM byte array which is by definition preinitialized
@@ -1005,7 +1000,7 @@
             throw new IllegalArgumentException("quality must be 0..100");
         }
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
-        boolean result = nativeCompress(mNativeBitmap, format.nativeInt, quality,
+        boolean result = nativeCompress(mSkBitmapPtr, format.nativeInt, quality,
                               stream, new byte[WORKING_COMPRESS_STORAGE]);
         Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         return result;
@@ -1022,12 +1017,12 @@
      * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied.
      * When a pixel is pre-multiplied, the RGB components have been multiplied by
      * the alpha component. For instance, if the original color is a 50%
-     * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is 
+     * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
      * <code>(128, 128, 0, 0)</code>.</p>
-     * 
+     *
      * <p>This method always returns false if {@link #getConfig()} is
      * {@link Bitmap.Config#RGB_565}.</p>
-     * 
+     *
      * <p>The return value is undefined if {@link #getConfig()} is
      * {@link Bitmap.Config#ALPHA_8}.</p>
      *
@@ -1046,7 +1041,7 @@
      * @see BitmapFactory.Options#inPremultiplied
      */
     public final boolean isPremultiplied() {
-        return nativeIsPremultiplied(mNativeBitmap);
+        return nativeIsPremultiplied(mSkBitmapPtr);
     }
 
     /**
@@ -1071,7 +1066,7 @@
      */
     public final void setPremultiplied(boolean premultiplied) {
         mRequestPremultiplied = premultiplied;
-        nativeSetPremultiplied(mNativeBitmap, premultiplied);
+        nativeSetPremultiplied(mSkBitmapPtr, premultiplied);
     }
 
     /** Returns the bitmap's width */
@@ -1137,7 +1132,7 @@
     public int getScaledHeight(int targetDensity) {
         return scaleFromDensity(getHeight(), mDensity, targetDensity);
     }
-    
+
     /**
      * @hide
      */
@@ -1145,11 +1140,11 @@
         if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
             return size;
         }
-        
+
         // Scale by tdensity / sdensity, rounding up.
         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
     }
-    
+
     /**
      * Return the number of bytes between rows in the bitmap's pixels. Note that
      * this refers to the pixels as stored natively by the bitmap. If you call
@@ -1163,7 +1158,7 @@
      * @return number of bytes between rows of the native bitmap pixels.
      */
     public final int getRowBytes() {
-        return nativeRowBytes(mNativeBitmap);
+        return nativeRowBytes(mSkBitmapPtr);
     }
 
     /**
@@ -1206,7 +1201,7 @@
      * that config, otherwise return null.
      */
     public final Config getConfig() {
-        return Config.nativeToConfig(nativeConfig(mNativeBitmap));
+        return Config.nativeToConfig(nativeConfig(mSkBitmapPtr));
     }
 
     /** Returns true if the bitmap's config supports per-pixel alpha, and
@@ -1218,7 +1213,7 @@
      * it will return true by default.
      */
     public final boolean hasAlpha() {
-        return nativeHasAlpha(mNativeBitmap);
+        return nativeHasAlpha(mSkBitmapPtr);
     }
 
     /**
@@ -1232,28 +1227,28 @@
      * non-opaque per-pixel alpha values.
      */
     public void setHasAlpha(boolean hasAlpha) {
-        nativeSetHasAlpha(mNativeBitmap, hasAlpha, mRequestPremultiplied);
+        nativeSetHasAlpha(mSkBitmapPtr, hasAlpha, mRequestPremultiplied);
     }
 
     /**
      * Indicates whether the renderer responsible for drawing this
      * bitmap should attempt to use mipmaps when this bitmap is drawn
      * scaled down.
-     * 
+     *
      * If you know that you are going to draw this bitmap at less than
      * 50% of its original size, you may be able to obtain a higher
      * quality
-     * 
+     *
      * This property is only a suggestion that can be ignored by the
      * renderer. It is not guaranteed to have any effect.
-     * 
+     *
      * @return true if the renderer should attempt to use mipmaps,
      *         false otherwise
-     * 
+     *
      * @see #setHasMipMap(boolean)
      */
     public final boolean hasMipMap() {
-        return nativeHasMipMap(mNativeBitmap);
+        return nativeHasMipMap(mSkBitmapPtr);
     }
 
     /**
@@ -1264,7 +1259,7 @@
      * If you know that you are going to draw this bitmap at less than
      * 50% of its original size, you may be able to obtain a higher
      * quality by turning this property on.
-     * 
+     *
      * Note that if the renderer respects this hint it might have to
      * allocate extra memory to hold the mipmap levels for this bitmap.
      *
@@ -1277,7 +1272,7 @@
      * @see #hasMipMap()
      */
     public final void setHasMipMap(boolean hasMipMap) {
-        nativeSetHasMipMap(mNativeBitmap, hasMipMap);
+        nativeSetHasMipMap(mSkBitmapPtr, hasMipMap);
     }
 
     /**
@@ -1285,12 +1280,12 @@
      *
      * @throws IllegalStateException if the bitmap is not mutable.
      */
-    public void eraseColor(int c) {
+    public void eraseColor(@ColorInt int c) {
         checkRecycled("Can't erase a recycled bitmap");
         if (!isMutable()) {
             throw new IllegalStateException("cannot erase immutable bitmaps");
         }
-        nativeErase(mNativeBitmap, c);
+        nativeErase(mSkBitmapPtr, c);
     }
 
     /**
@@ -1303,10 +1298,11 @@
      * @return     The argb {@link Color} at the specified coordinate
      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
      */
+    @ColorInt
     public int getPixel(int x, int y) {
         checkRecycled("Can't call getPixel() on a recycled bitmap");
         checkPixelAccess(x, y);
-        return nativeGetPixel(mNativeBitmap, x, y);
+        return nativeGetPixel(mSkBitmapPtr, x, y);
     }
 
     /**
@@ -1332,21 +1328,21 @@
      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
      *         to receive the specified number of pixels.
      */
-    public void getPixels(int[] pixels, int offset, int stride,
+    public void getPixels(@ColorInt int[] pixels, int offset, int stride,
                           int x, int y, int width, int height) {
         checkRecycled("Can't call getPixels() on a recycled bitmap");
         if (width == 0 || height == 0) {
             return; // nothing to do
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
-        nativeGetPixels(mNativeBitmap, pixels, offset, stride,
+        nativeGetPixels(mSkBitmapPtr, pixels, offset, stride,
                         x, y, width, height);
     }
 
     /**
      * Shared code to check for illegal arguments passed to getPixel()
      * or setPixel()
-     * 
+     *
      * @param x x coordinate of the pixel
      * @param y y coordinate of the pixel
      */
@@ -1414,13 +1410,13 @@
      * @throws IllegalArgumentException if x, y are outside of the bitmap's
      *         bounds.
      */
-    public void setPixel(int x, int y, int color) {
+    public void setPixel(int x, int y, @ColorInt int color) {
         checkRecycled("Can't call setPixel() on a recycled bitmap");
         if (!isMutable()) {
             throw new IllegalStateException();
         }
         checkPixelAccess(x, y);
-        nativeSetPixel(mNativeBitmap, x, y, color);
+        nativeSetPixel(mSkBitmapPtr, x, y, color);
     }
 
     /**
@@ -1446,7 +1442,7 @@
      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
      *         to receive the specified number of pixels.
      */
-    public void setPixels(int[] pixels, int offset, int stride,
+    public void setPixels(@ColorInt int[] pixels, int offset, int stride,
             int x, int y, int width, int height) {
         checkRecycled("Can't call setPixels() on a recycled bitmap");
         if (!isMutable()) {
@@ -1456,7 +1452,7 @@
             return; // nothing to do
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
-        nativeSetPixels(mNativeBitmap, pixels, offset, stride,
+        nativeSetPixels(mSkBitmapPtr, pixels, offset, stride,
                         x, y, width, height);
     }
 
@@ -1494,7 +1490,7 @@
      */
     public void writeToParcel(Parcel p, int flags) {
         checkRecycled("Can't parcel a recycled bitmap");
-        if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) {
+        if (!nativeWriteToParcel(mSkBitmapPtr, mIsMutable, mDensity, p)) {
             throw new RuntimeException("native writeToParcel failed");
         }
     }
@@ -1506,6 +1502,7 @@
      *
      * @return new bitmap containing the alpha channel of the original bitmap.
      */
+    @CheckResult
     public Bitmap extractAlpha() {
         return extractAlpha(null, null);
     }
@@ -1522,9 +1519,9 @@
      * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
      * drawing the original would result in the blur visually aligning with
      * the original.
-     * 
+     *
      * <p>The initial density of the returned bitmap is the same as the original's.
-     * 
+     *
      * @param paint Optional paint used to modify the alpha values in the
      *              resulting bitmap. Pass null for default behavior.
      * @param offsetXY Optional array that returns the X (index 0) and Y
@@ -1535,10 +1532,11 @@
      *         Canvas.drawBitmap(), where the color(s) will be taken from the
      *         paint that is passed to the draw call.
      */
+    @CheckResult
     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
         checkRecycled("Can't extractAlpha on a recycled bitmap");
         long nativePaint = paint != null ? paint.getNativeInstance() : 0;
-        Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY);
+        Bitmap bm = nativeExtractAlpha(mSkBitmapPtr, nativePaint, offsetXY);
         if (bm == null) {
             throw new RuntimeException("Failed to extractAlpha on Bitmap");
         }
@@ -1552,7 +1550,7 @@
      *  If other is null, return false.
      */
     public boolean sameAs(Bitmap other) {
-        return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap));
+        return this == other || (other != null && nativeSameAs(mSkBitmapPtr, other.mSkBitmapPtr));
     }
 
     /**
@@ -1567,7 +1565,12 @@
      * and therefore is harmless.
      */
     public void prepareToDraw() {
-        nativePrepareToDraw(mNativeBitmap);
+        nativePrepareToDraw(mSkBitmapPtr);
+    }
+
+    /** @hide */
+    public final long getSkBitmap() {
+        return mSkBitmapPtr;
     }
 
     private static class BitmapFinalizer {
@@ -1658,8 +1661,4 @@
     private static native boolean nativeHasMipMap(long nativeBitmap);
     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
-
-    /* package */ final long ni() {
-        return mNativeBitmap;
-    }
 }
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index 5e004a3..f2f890e 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -42,7 +42,7 @@
         mBitmap = bitmap;
         mTileX = tileX;
         mTileY = tileY;
-        final long b = bitmap.ni();
+        final long b = bitmap.getSkBitmap();
         init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
     }
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index e4c2f0e..150f195 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -16,9 +16,11 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
 import android.text.SpannedString;
@@ -154,7 +156,7 @@
             throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
         }
         throwIfCannotDraw(bitmap);
-        mNativeCanvasWrapper = initRaster(bitmap.ni());
+        mNativeCanvasWrapper = initRaster(bitmap.getSkBitmap());
         mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
         mBitmap = bitmap;
         mDensity = bitmap.mDensity;
@@ -219,7 +221,7 @@
             }
             throwIfCannotDraw(bitmap);
 
-            native_setBitmap(mNativeCanvasWrapper, bitmap.ni(), true);
+            native_setBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), true);
             mDensity = bitmap.mDensity;
         }
 
@@ -1012,7 +1014,7 @@
      *
      * @param color the color to draw onto the canvas
      */
-    public void drawColor(int color) {
+    public void drawColor(@ColorInt int color) {
         native_drawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
     }
 
@@ -1023,7 +1025,7 @@
      * @param color the color to draw with
      * @param mode  the porter-duff mode to apply to the color
      */
-    public void drawColor(int color, @NonNull PorterDuff.Mode mode) {
+    public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
         native_drawColor(mNativeCanvasWrapper, color, mode.nativeInt);
     }
 
@@ -1054,14 +1056,15 @@
      *                 "points" that are drawn is really (count >> 1).
      * @param paint    The paint used to draw the points
      */
-    public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) {
+    public void drawPoints(@Size(multiple=2) float[] pts, int offset, int count,
+            @NonNull Paint paint) {
         native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
     /**
      * Helper for drawPoints() that assumes you want to draw the entire array
      */
-    public void drawPoints(@NonNull float[] pts, @NonNull Paint paint) {
+    public void drawPoints(@Size(multiple=2) @NonNull float[] pts, @NonNull Paint paint) {
         drawPoints(pts, 0, pts.length, paint);
     }
 
@@ -1104,11 +1107,11 @@
      *                 (count >> 2).
      * @param paint    The paint used to draw the points
      */
-    public void drawLines(float[] pts, int offset, int count, Paint paint) {
+    public void drawLines(@Size(min=4,multiple=2) float[] pts, int offset, int count, Paint paint) {
         native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
-    public void drawLines(@NonNull float[] pts, @NonNull Paint paint) {
+    public void drawLines(@Size(min=4,multiple=2) @NonNull float[] pts, @NonNull Paint paint) {
         drawLines(pts, 0, pts.length, paint);
     }
 
@@ -1339,7 +1342,7 @@
      */
     public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
         throwIfCannotDraw(bitmap);
-        native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top,
+        native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top,
                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity);
     }
 
@@ -1385,7 +1388,7 @@
           bottom = src.bottom;
       }
 
-      native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom,
+      native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
               dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
               bitmap.mDensity);
   }
@@ -1432,7 +1435,7 @@
             bottom = src.bottom;
         }
 
-        native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom,
+        native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
             dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
             bitmap.mDensity);
     }
@@ -1513,7 +1516,7 @@
      * @param paint  May be null. The paint used to draw the bitmap
      */
     public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
-        nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(),
+        nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getSkBitmap(), matrix.ni(),
                 paint != null ? paint.getNativeInstance() : 0);
     }
 
@@ -1568,7 +1571,7 @@
             // no mul by 2, since we need only 1 color per vertex
             checkRange(colors.length, colorOffset, count);
         }
-        nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.ni(), meshWidth, meshHeight,
+        nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getSkBitmap(), meshWidth, meshHeight,
                 verts, vertOffset, colors, colorOffset,
                 paint != null ? paint.getNativeInstance() : 0);
     }
@@ -1828,7 +1831,8 @@
      * @param paint    The paint used for the text (e.g. color, size, style)
      */
     @Deprecated
-    public void drawPosText(@NonNull char[] text, int index, int count, @NonNull float[] pos,
+    public void drawPosText(@NonNull char[] text, int index, int count,
+            @NonNull @Size(multiple=2) float[] pos,
             @NonNull Paint paint) {
         if (index < 0 || index + count > text.length || count*2 > pos.length) {
             throw new IndexOutOfBoundsException();
@@ -1851,7 +1855,8 @@
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     @Deprecated
-    public void drawPosText(@NonNull String text, @NonNull float[] pos, @NonNull Paint paint) {
+    public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos,
+            @NonNull Paint paint) {
         drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
     }
 
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 3fe5672..666dbd8 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
+import android.annotation.Size;
 import android.util.MathUtils;
 import com.android.internal.util.XmlUtils;
 
@@ -35,23 +37,24 @@
  * 0xFFFFFFFF
  */
 public class Color {
-    public static final int BLACK       = 0xFF000000;
-    public static final int DKGRAY      = 0xFF444444;
-    public static final int GRAY        = 0xFF888888;
-    public static final int LTGRAY      = 0xFFCCCCCC;
-    public static final int WHITE       = 0xFFFFFFFF;
-    public static final int RED         = 0xFFFF0000;
-    public static final int GREEN       = 0xFF00FF00;
-    public static final int BLUE        = 0xFF0000FF;
-    public static final int YELLOW      = 0xFFFFFF00;
-    public static final int CYAN        = 0xFF00FFFF;
-    public static final int MAGENTA     = 0xFFFF00FF;
-    public static final int TRANSPARENT = 0;
+    @ColorInt public static final int BLACK       = 0xFF000000;
+    @ColorInt public static final int DKGRAY      = 0xFF444444;
+    @ColorInt public static final int GRAY        = 0xFF888888;
+    @ColorInt public static final int LTGRAY      = 0xFFCCCCCC;
+    @ColorInt public static final int WHITE       = 0xFFFFFFFF;
+    @ColorInt public static final int RED         = 0xFFFF0000;
+    @ColorInt public static final int GREEN       = 0xFF00FF00;
+    @ColorInt public static final int BLUE        = 0xFF0000FF;
+    @ColorInt public static final int YELLOW      = 0xFFFFFF00;
+    @ColorInt public static final int CYAN        = 0xFF00FFFF;
+    @ColorInt public static final int MAGENTA     = 0xFFFF00FF;
+    @ColorInt public static final int TRANSPARENT = 0;
 
     /**
      * Return the alpha component of a color int. This is the same as saying
      * color >>> 24
      */
+    @ColorInt
     public static int alpha(int color) {
         return color >>> 24;
     }
@@ -60,6 +63,7 @@
      * Return the red component of a color int. This is the same as saying
      * (color >> 16) & 0xFF
      */
+    @ColorInt
     public static int red(int color) {
         return (color >> 16) & 0xFF;
     }
@@ -68,6 +72,7 @@
      * Return the green component of a color int. This is the same as saying
      * (color >> 8) & 0xFF
      */
+    @ColorInt
     public static int green(int color) {
         return (color >> 8) & 0xFF;
     }
@@ -76,6 +81,7 @@
      * Return the blue component of a color int. This is the same as saying
      * color & 0xFF
      */
+    @ColorInt
     public static int blue(int color) {
         return color & 0xFF;
     }
@@ -90,6 +96,7 @@
      * @param green Green component [0..255] of the color
      * @param blue  Blue component [0..255] of the color
      */
+    @ColorInt
     public static int rgb(int red, int green, int blue) {
         return (0xFF << 24) | (red << 16) | (green << 8) | blue;
     }
@@ -104,6 +111,7 @@
      * @param green Green component [0..255] of the color
      * @param blue  Blue component [0..255] of the color
      */
+    @ColorInt
     public static int argb(int alpha, int red, int green, int blue) {
         return (alpha << 24) | (red << 16) | (green << 8) | blue;
     }
@@ -115,7 +123,7 @@
      * 
      * @hide Pending API council
      */
-    public static float hue(int color) {
+    public static float hue(@ColorInt int color) {
         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
@@ -157,7 +165,7 @@
      * 
      * @hide Pending API council
      */
-    public static float saturation(int color) {
+    public static float saturation(@ColorInt int color) {
         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
@@ -184,7 +192,7 @@
      *
      * @hide Pending API council
      */
-    public static float brightness(int color) {
+    public static float brightness(@ColorInt int color) {
         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
@@ -206,7 +214,8 @@
      * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple',
      * 'silver', 'teal'.
      */
-    public static int parseColor(String colorString) {
+    @ColorInt
+    public static int parseColor(@Size(min=1) String colorString) {
         if (colorString.charAt(0) == '#') {
             // Use a long to avoid rollovers on #ffXXXXXX
             long color = Long.parseLong(colorString.substring(1), 16);
@@ -237,7 +246,8 @@
      * 
      * @hide Pending API council
      */
-    public static int HSBtoColor(float[] hsb) {
+    @ColorInt
+    public static int HSBtoColor(@Size(3) float[] hsb) {
         return HSBtoColor(hsb[0], hsb[1], hsb[2]);
     }
     
@@ -254,6 +264,7 @@
      * 
      * @hide Pending API council
      */
+    @ColorInt
     public static int HSBtoColor(float h, float s, float b) {
         h = MathUtils.constrain(h, 0.0f, 1.0f);
         s = MathUtils.constrain(s, 0.0f, 1.0f);
@@ -317,7 +328,7 @@
      * @param blue  blue component value [0..255]
      * @param hsv  3 element array which holds the resulting HSV components.
      */
-    public static void RGBToHSV(int red, int green, int blue, float hsv[]) {
+    public static void RGBToHSV(int red, int green, int blue, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -332,7 +343,7 @@
      * @param color the argb color to convert. The alpha component is ignored.
      * @param hsv  3 element array which holds the resulting HSV components.
      */
-    public static void colorToHSV(int color, float hsv[]) {
+    public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[]) {
         RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv);
     }
 
@@ -345,7 +356,7 @@
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
     */
-    public static int HSVToColor(float hsv[]) {
+    public static int HSVToColor(@Size(3) float hsv[]) {
         return HSVToColor(0xFF, hsv);
     }
 
@@ -360,7 +371,7 @@
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
     */
-    public static int HSVToColor(int alpha, float hsv[]) {
+    public static int HSVToColor(int alpha, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -379,6 +390,7 @@
      *
      * @hide
      */
+    @ColorInt
     public static int getHtmlColor(String color) {
         Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT));
         if (i != null) {
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 3efb9c0..49c4247 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -356,6 +356,38 @@
     public static final int RAW10 = 0x25;
 
     /**
+     * Android dense depth image format.
+     *
+     * Each pixel is 16 bits, representing a depth ranging measurement from
+     * a depth camera or similar sensor.
+     *
+     * <p>This format assumes
+     * <ul>
+     * <li>an even width</li>
+     * <li>an even height</li>
+     * <li>a horizontal stride multiple of 16 pixels</li>
+     * </ul>
+     * </p>
+     *
+     * <pre> y_size = stride * height </pre>
+     *
+     * When produced by a camera, the units are millimeters.
+     */
+    public static final int DEPTH16 = 0x44363159;
+
+    /**
+     * Android sparse depth point cloud format.
+     *
+     * <p>A variable-length list of 3D points, with each point represented
+     * by a triple of floats.</p>
+     *
+     * <p>The number of points is {@code (size of the buffer in bytes) / 12}.
+     *
+     * The coordinate system and units depend on the source of the point cloud data.
+     */
+    public static final int DEPTH_POINT_CLOUD = 0x101;
+
+    /**
      * Use this function to retrieve the number of bits per pixel of an
      * ImageFormat.
      *
@@ -376,6 +408,7 @@
             case Y8:
                 return 8;
             case Y16:
+            case DEPTH16:
                 return 16;
             case NV21:
                 return 12;
@@ -412,6 +445,8 @@
             case YUV_420_888:
             case RAW_SENSOR:
             case RAW10:
+            case DEPTH16:
+            case DEPTH_POINT_CLOUD:
                 return true;
         }
 
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index ebc86aa..9c4299a 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -98,7 +98,7 @@
     public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
         mBitmap = bitmap;
         mSrcName = srcName;
-        mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk);
+        mNativeChunk = validateNinePatchChunk(mBitmap.getSkBitmap(), chunk);
     }
 
     /**
@@ -199,12 +199,12 @@
     }
 
     void drawSoftware(Canvas canvas, RectF location, Paint paint) {
-        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
+        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
                 paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
     void drawSoftware(Canvas canvas, Rect location, Paint paint) {
-        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
+        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
                 paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
@@ -252,7 +252,7 @@
      * that are transparent.
      */
     public final Region getTransparentRegion(Rect bounds) {
-        long r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds);
+        long r = nativeGetTransparentRegion(mBitmap.getSkBitmap(), mNativeChunk, bounds);
         return r != 0 ? new Region(r) : null;
     }
 
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index f76184f..aa40408 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.graphics.drawable.Drawable;
 
@@ -101,7 +102,7 @@
      * assumed by the drawing system to fully cover content beneath it,
      * meaning content beneath may be optimized away.
      */
-    public void setAlpha(float alpha) {
+    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         mAlpha = alpha;
     }
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 91c8dba..0656b2e 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
 import android.text.SpannedString;
@@ -534,8 +535,9 @@
      * @hide
      */
     public long getNativeInstance() {
-        if (mShader != null && mShader.getNativeInstance() != mNativeShader) {
-            mNativeShader = mShader.getNativeInstance();
+        long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance();
+        if (newNativeShader != mNativeShader) {
+            mNativeShader = newNativeShader;
             native_setShader(mNativePaint, mNativeShader);
         }
         return mNativePaint;
@@ -776,6 +778,7 @@
      *
      * @return the paint's color (and alpha).
      */
+    @ColorInt
     public native int getColor();
 
     /**
@@ -786,7 +789,7 @@
      *
      * @param color The new color (including alpha) to set in the paint.
      */
-    public native void setColor(int color);
+    public native void setColor(@ColorInt int color);
 
     /**
      * Helper to getColor() that just returns the color's alpha value. This is
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
index 2ef1662..dcccf35 100644
--- a/graphics/java/android/graphics/PorterDuff.java
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -18,7 +18,7 @@
 
 public class PorterDuff {
 
-    // these value must match their native equivalents. See SkPorterDuff.h
+    // these value must match their native equivalents. See SkXfermode.h
     public enum Mode {
         /** [0, 0] */
         CLEAR       (0),
@@ -46,17 +46,17 @@
         XOR         (11),
         /** [Sa + Da - Sa*Da,
              Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
-        DARKEN      (12),
+        DARKEN      (16),
         /** [Sa + Da - Sa*Da,
              Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
-        LIGHTEN     (13),
+        LIGHTEN     (17),
         /** [Sa * Da, Sc * Dc] */
-        MULTIPLY    (14),
+        MULTIPLY    (13),
         /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
-        SCREEN      (15),
+        SCREEN      (14),
         /** Saturate(S + D) */
-        ADD         (16),
-        OVERLAY     (17);
+        ADD         (12),
+        OVERLAY     (15);
 
         Mode(int nativeInt) {
             this.nativeInt = nativeInt;
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 85e02b7..f75ab36 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.graphics.*;
 import android.graphics.PorterDuff.Mode;
@@ -62,7 +63,7 @@
      *
      * @param color The color to draw.
      */
-    public ColorDrawable(int color) {
+    public ColorDrawable(@ColorInt int color) {
         mColorState = new ColorState();
 
         setColor(color);
@@ -117,6 +118,7 @@
      *
      * @return int The color to draw.
      */
+    @ColorInt
     public int getColor() {
         return mColorState.mUseColor;
     }
@@ -128,7 +130,7 @@
      *
      * @param color The color to draw.
      */
-    public void setColor(int color) {
+    public void setColor(@ColorInt int color) {
         if (mColorState.mBaseColor != color || mColorState.mUseColor != color) {
             mColorState.mBaseColor = mColorState.mUseColor = color;
             invalidateSelf();
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 2cc192c..16760c7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.ColorStateList;
@@ -544,7 +545,7 @@
      * @see #setTintList(ColorStateList)
      * @see #setTintMode(PorterDuff.Mode)
      */
-    public void setTint(int tintColor) {
+    public void setTint(@ColorInt int tintColor) {
         setTintList(ColorStateList.valueOf(tintColor));
     }
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 6ea23d4..eff152c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.ColorInt;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -181,7 +182,7 @@
      * Create a new gradient drawable given an orientation and an array
      * of colors for the gradient.
      */
-    public GradientDrawable(Orientation orientation, int[] colors) {
+    public GradientDrawable(Orientation orientation, @ColorInt int[] colors) {
         this(new GradientState(orientation, colors), null);
     }
 
@@ -250,7 +251,7 @@
      * @see #mutate()
      * @see #setStroke(int, int, float, float)
      */
-    public void setStroke(int width, int color) {
+    public void setStroke(int width, @ColorInt int color) {
         setStroke(width, color, 0, 0);
     }
 
@@ -286,7 +287,7 @@
      * @see #mutate()
      * @see #setStroke(int, int)
      */
-    public void setStroke(int width, int color, float dashWidth, float dashGap) {
+    public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) {
         mGradientState.setStroke(width, ColorStateList.valueOf(color), dashWidth, dashGap);
         setStrokeInternal(width, color, dashWidth, dashGap);
     }
@@ -501,7 +502,7 @@
      * @see #mutate()
      * @see #setColor(int)
      */
-    public void setColors(int[] colors) {
+    public void setColors(@ColorInt int[] colors) {
         mGradientState.setColors(colors);
         mGradientIsDirty = true;
         invalidateSelf();
@@ -713,7 +714,7 @@
      * @see #mutate()
      * @see #setColors(int[])
      */
-    public void setColor(int argb) {
+    public void setColor(@ColorInt int argb) {
         mGradientState.setColorStateList(ColorStateList.valueOf(argb));
         mFillPaint.setColor(argb);
         invalidateSelf();
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
deleted file mode 100644
index 138d73a..0000000
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ /dev/null
@@ -1,578 +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.graphics.drawable;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.graphics.Canvas;
-import android.graphics.CanvasProperty;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.MathUtils;
-import android.view.HardwareCanvas;
-import android.view.RenderNodeAnimator;
-import android.view.animation.LinearInterpolator;
-
-import java.util.ArrayList;
-
-/**
- * Draws a Material ripple.
- */
-class Ripple {
-    private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator();
-
-    private static final float GLOBAL_SPEED = 1.0f;
-    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED;
-    private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED;
-    private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
-
-    private static final long RIPPLE_ENTER_DELAY = 80;
-
-    // Hardware animators.
-    private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
-
-    private final RippleDrawable mOwner;
-
-    /** Bounds used for computing max radius. */
-    private final Rect mBounds;
-
-    /** Maximum ripple radius. */
-    private float mOuterRadius;
-
-    /** Screen density used to adjust pixel-based velocities. */
-    private float mDensity;
-
-    private float mStartingX;
-    private float mStartingY;
-    private float mClampedStartingX;
-    private float mClampedStartingY;
-
-    // Hardware rendering properties.
-    private CanvasProperty<Paint> mPropPaint;
-    private CanvasProperty<Float> mPropRadius;
-    private CanvasProperty<Float> mPropX;
-    private CanvasProperty<Float> mPropY;
-
-    // Software animators.
-    private ObjectAnimator mAnimRadius;
-    private ObjectAnimator mAnimOpacity;
-    private ObjectAnimator mAnimX;
-    private ObjectAnimator mAnimY;
-
-    // Temporary paint used for creating canvas properties.
-    private Paint mTempPaint;
-
-    // Software rendering properties.
-    private float mOpacity = 1;
-    private float mOuterX;
-    private float mOuterY;
-
-    // Values used to tween between the start and end positions.
-    private float mTweenRadius = 0;
-    private float mTweenX = 0;
-    private float mTweenY = 0;
-
-    /** Whether we should be drawing hardware animations. */
-    private boolean mHardwareAnimating;
-
-    /** Whether we can use hardware acceleration for the exit animation. */
-    private boolean mCanUseHardware;
-
-    /** Whether we have an explicit maximum radius. */
-    private boolean mHasMaxRadius;
-
-    /** Whether we were canceled externally and should avoid self-removal. */
-    private boolean mCanceled;
-
-    private boolean mHasPendingHardwareExit;
-    private int mPendingRadiusDuration;
-    private int mPendingOpacityDuration;
-
-    /**
-     * Creates a new ripple.
-     */
-    public Ripple(RippleDrawable owner, Rect bounds, float startingX, float startingY) {
-        mOwner = owner;
-        mBounds = bounds;
-
-        mStartingX = startingX;
-        mStartingY = startingY;
-    }
-
-    public void setup(float maxRadius, float density) {
-        if (maxRadius >= 0) {
-            mHasMaxRadius = true;
-            mOuterRadius = maxRadius;
-        } else {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-        }
-
-        mOuterX = 0;
-        mOuterY = 0;
-        mDensity = density;
-
-        clampStartingPosition();
-    }
-
-    public boolean isHardwareAnimating() {
-        return mHardwareAnimating;
-    }
-
-    private void clampStartingPosition() {
-        final float cX = mBounds.exactCenterX();
-        final float cY = mBounds.exactCenterY();
-        final float dX = mStartingX - cX;
-        final float dY = mStartingY - cY;
-        final float r = mOuterRadius;
-        if (dX * dX + dY * dY > r * r) {
-            // Point is outside the circle, clamp to the circumference.
-            final double angle = Math.atan2(dY, dX);
-            mClampedStartingX = cX + (float) (Math.cos(angle) * r);
-            mClampedStartingY = cY + (float) (Math.sin(angle) * r);
-        } else {
-            mClampedStartingX = mStartingX;
-            mClampedStartingY = mStartingY;
-        }
-    }
-
-    public void onHotspotBoundsChanged() {
-        if (!mHasMaxRadius) {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-
-            clampStartingPosition();
-        }
-    }
-
-    public void setOpacity(float a) {
-        mOpacity = a;
-        invalidateSelf();
-    }
-
-    public float getOpacity() {
-        return mOpacity;
-    }
-
-    @SuppressWarnings("unused")
-    public void setRadiusGravity(float r) {
-        mTweenRadius = r;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getRadiusGravity() {
-        return mTweenRadius;
-    }
-
-    @SuppressWarnings("unused")
-    public void setXGravity(float x) {
-        mTweenX = x;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getXGravity() {
-        return mTweenX;
-    }
-
-    @SuppressWarnings("unused")
-    public void setYGravity(float y) {
-        mTweenY = y;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getYGravity() {
-        return mTweenY;
-    }
-
-    /**
-     * Draws the ripple centered at (0,0) using the specified paint.
-     */
-    public boolean draw(Canvas c, Paint p) {
-        final boolean canUseHardware = c.isHardwareAccelerated();
-        if (mCanUseHardware != canUseHardware && mCanUseHardware) {
-            // We've switched from hardware to non-hardware mode. Panic.
-            cancelHardwareAnimations(true);
-        }
-        mCanUseHardware = canUseHardware;
-
-        final boolean hasContent;
-        if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) {
-            hasContent = drawHardware((HardwareCanvas) c, p);
-        } else {
-            hasContent = drawSoftware(c, p);
-        }
-
-        return hasContent;
-    }
-
-    private boolean drawHardware(HardwareCanvas c, Paint p) {
-        if (mHasPendingHardwareExit) {
-            cancelHardwareAnimations(false);
-            startPendingHardwareExit(c, p);
-        }
-
-        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
-
-        return true;
-    }
-
-    private boolean drawSoftware(Canvas c, Paint p) {
-        boolean hasContent = false;
-
-        final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * mOpacity + 0.5f);
-        final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
-        if (alpha > 0 && radius > 0) {
-            final float x = MathUtils.lerp(
-                    mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
-            final float y = MathUtils.lerp(
-                    mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
-            p.setAlpha(alpha);
-            c.drawCircle(x, y, radius, p);
-            p.setAlpha(paintAlpha);
-            hasContent = true;
-        }
-
-        return hasContent;
-    }
-
-    /**
-     * Returns the maximum bounds of the ripple relative to the ripple center.
-     */
-    public void getBounds(Rect bounds) {
-        final int outerX = (int) mOuterX;
-        final int outerY = (int) mOuterY;
-        final int r = (int) mOuterRadius + 1;
-        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
-    }
-
-    /**
-     * Specifies the starting position relative to the drawable bounds. No-op if
-     * the ripple has already entered.
-     */
-    public void move(float x, float y) {
-        mStartingX = x;
-        mStartingY = y;
-
-        clampStartingPosition();
-    }
-
-    /**
-     * Starts the enter animation.
-     */
-    public void enter() {
-        cancel();
-
-        final int radiusDuration = (int)
-                (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
-
-        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
-        radius.setAutoCancel(true);
-        radius.setDuration(radiusDuration);
-        radius.setInterpolator(LINEAR_INTERPOLATOR);
-        radius.setStartDelay(RIPPLE_ENTER_DELAY);
-
-        final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1);
-        cX.setAutoCancel(true);
-        cX.setDuration(radiusDuration);
-        cX.setInterpolator(LINEAR_INTERPOLATOR);
-        cX.setStartDelay(RIPPLE_ENTER_DELAY);
-
-        final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "yGravity", 1);
-        cY.setAutoCancel(true);
-        cY.setDuration(radiusDuration);
-        cY.setInterpolator(LINEAR_INTERPOLATOR);
-        cY.setStartDelay(RIPPLE_ENTER_DELAY);
-
-        mAnimRadius = radius;
-        mAnimX = cX;
-        mAnimY = cY;
-
-        // Enter animations always run on the UI thread, since it's unlikely
-        // that anything interesting is happening until the user lifts their
-        // finger.
-        radius.start();
-        cX.start();
-        cY.start();
-    }
-
-    /**
-     * Starts the exit animation.
-     */
-    public void exit() {
-        final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
-        final float remaining;
-        if (mAnimRadius != null && mAnimRadius.isRunning()) {
-            remaining = mOuterRadius - radius;
-        } else {
-            remaining = mOuterRadius;
-        }
-
-        cancel();
-
-        final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
-                + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
-        final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
-
-        if (mCanUseHardware) {
-            createPendingHardwareExit(radiusDuration, opacityDuration);
-        } else {
-            exitSoftware(radiusDuration, opacityDuration);
-        }
-    }
-
-    private void createPendingHardwareExit(int radiusDuration, int opacityDuration) {
-        mHasPendingHardwareExit = true;
-        mPendingRadiusDuration = radiusDuration;
-        mPendingOpacityDuration = opacityDuration;
-
-        // The animation will start on the next draw().
-        invalidateSelf();
-    }
-
-    private void startPendingHardwareExit(HardwareCanvas c, Paint p) {
-        mHasPendingHardwareExit = false;
-
-        final int radiusDuration = mPendingRadiusDuration;
-        final int opacityDuration = mPendingOpacityDuration;
-
-        final float startX = MathUtils.lerp(
-                mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
-        final float startY = MathUtils.lerp(
-                mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
-
-        final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
-        final Paint paint = getTempPaint(p);
-        paint.setAlpha((int) (paint.getAlpha() * mOpacity + 0.5f));
-        mPropPaint = CanvasProperty.createPaint(paint);
-        mPropRadius = CanvasProperty.createFloat(startRadius);
-        mPropX = CanvasProperty.createFloat(startX);
-        mPropY = CanvasProperty.createFloat(startY);
-
-        final RenderNodeAnimator radiusAnim = new RenderNodeAnimator(mPropRadius, mOuterRadius);
-        radiusAnim.setDuration(radiusDuration);
-        radiusAnim.setInterpolator(DECEL_INTERPOLATOR);
-        radiusAnim.setTarget(c);
-        radiusAnim.start();
-
-        final RenderNodeAnimator xAnim = new RenderNodeAnimator(mPropX, mOuterX);
-        xAnim.setDuration(radiusDuration);
-        xAnim.setInterpolator(DECEL_INTERPOLATOR);
-        xAnim.setTarget(c);
-        xAnim.start();
-
-        final RenderNodeAnimator yAnim = new RenderNodeAnimator(mPropY, mOuterY);
-        yAnim.setDuration(radiusDuration);
-        yAnim.setInterpolator(DECEL_INTERPOLATOR);
-        yAnim.setTarget(c);
-        yAnim.start();
-
-        final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPropPaint,
-                RenderNodeAnimator.PAINT_ALPHA, 0);
-        opacityAnim.setDuration(opacityDuration);
-        opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-        opacityAnim.addListener(mAnimationListener);
-        opacityAnim.setTarget(c);
-        opacityAnim.start();
-
-        mRunningAnimations.add(radiusAnim);
-        mRunningAnimations.add(opacityAnim);
-        mRunningAnimations.add(xAnim);
-        mRunningAnimations.add(yAnim);
-
-        mHardwareAnimating = true;
-
-        // Set up the software values to match the hardware end values.
-        mOpacity = 0;
-        mTweenX = 1;
-        mTweenY = 1;
-        mTweenRadius = 1;
-    }
-
-    /**
-     * Jump all animations to their end state. The caller is responsible for
-     * removing the ripple from the list of animating ripples.
-     */
-    public void jump() {
-        mCanceled = true;
-        endSoftwareAnimations();
-        cancelHardwareAnimations(true);
-        mCanceled = false;
-    }
-
-    private void endSoftwareAnimations() {
-        if (mAnimRadius != null) {
-            mAnimRadius.end();
-            mAnimRadius = null;
-        }
-
-        if (mAnimOpacity != null) {
-            mAnimOpacity.end();
-            mAnimOpacity = null;
-        }
-
-        if (mAnimX != null) {
-            mAnimX.end();
-            mAnimX = null;
-        }
-
-        if (mAnimY != null) {
-            mAnimY.end();
-            mAnimY = null;
-        }
-    }
-
-    private Paint getTempPaint(Paint original) {
-        if (mTempPaint == null) {
-            mTempPaint = new Paint();
-        }
-        mTempPaint.set(original);
-        return mTempPaint;
-    }
-
-    private void exitSoftware(int radiusDuration, int opacityDuration) {
-        final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
-        radiusAnim.setAutoCancel(true);
-        radiusAnim.setDuration(radiusDuration);
-        radiusAnim.setInterpolator(DECEL_INTERPOLATOR);
-
-        final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1);
-        xAnim.setAutoCancel(true);
-        xAnim.setDuration(radiusDuration);
-        xAnim.setInterpolator(DECEL_INTERPOLATOR);
-
-        final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1);
-        yAnim.setAutoCancel(true);
-        yAnim.setDuration(radiusDuration);
-        yAnim.setInterpolator(DECEL_INTERPOLATOR);
-
-        final ObjectAnimator opacityAnim = ObjectAnimator.ofFloat(this, "opacity", 0);
-        opacityAnim.setAutoCancel(true);
-        opacityAnim.setDuration(opacityDuration);
-        opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-        opacityAnim.addListener(mAnimationListener);
-
-        mAnimRadius = radiusAnim;
-        mAnimOpacity = opacityAnim;
-        mAnimX = xAnim;
-        mAnimY = yAnim;
-
-        radiusAnim.start();
-        opacityAnim.start();
-        xAnim.start();
-        yAnim.start();
-    }
-
-    /**
-     * Cancels all animations. The caller is responsible for removing
-     * the ripple from the list of animating ripples.
-     */
-    public void cancel() {
-        mCanceled = true;
-        cancelSoftwareAnimations();
-        cancelHardwareAnimations(false);
-        mCanceled = false;
-    }
-
-    private void cancelSoftwareAnimations() {
-        if (mAnimRadius != null) {
-            mAnimRadius.cancel();
-            mAnimRadius = null;
-        }
-
-        if (mAnimOpacity != null) {
-            mAnimOpacity.cancel();
-            mAnimOpacity = null;
-        }
-
-        if (mAnimX != null) {
-            mAnimX.cancel();
-            mAnimX = null;
-        }
-
-        if (mAnimY != null) {
-            mAnimY.cancel();
-            mAnimY = null;
-        }
-    }
-
-    /**
-     * Cancels any running hardware animations.
-     */
-    private void cancelHardwareAnimations(boolean jumpToEnd) {
-        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
-        final int N = runningAnimations.size();
-        for (int i = 0; i < N; i++) {
-            if (jumpToEnd) {
-                runningAnimations.get(i).end();
-            } else {
-                runningAnimations.get(i).cancel();
-            }
-        }
-        runningAnimations.clear();
-
-        if (mHasPendingHardwareExit) {
-            // If we had a pending hardware exit, jump to the end state.
-            mHasPendingHardwareExit = false;
-
-            if (jumpToEnd) {
-                mOpacity = 0;
-                mTweenX = 1;
-                mTweenY = 1;
-                mTweenRadius = 1;
-            }
-        }
-
-        mHardwareAnimating = false;
-    }
-
-    private void removeSelf() {
-        // The owner will invalidate itself.
-        if (!mCanceled) {
-            mOwner.removeRipple(this);
-        }
-    }
-
-    private void invalidateSelf() {
-        mOwner.invalidateSelf();
-    }
-
-    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            removeSelf();
-        }
-    };
-
-    /**
-    * Interpolator with a smooth log deceleration
-    */
-    private static final class LogInterpolator implements TimeInterpolator {
-        @Override
-        public float getInterpolation(float input) {
-            return 1 - (float) Math.pow(400, -input * 1.4);
-        }
-    }
-}
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index ef35289..6d1b1fe 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -17,432 +17,162 @@
 package android.graphics.drawable;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.util.MathUtils;
+import android.util.FloatProperty;
 import android.view.HardwareCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.animation.LinearInterpolator;
 
-import java.util.ArrayList;
-
 /**
- * Draws a Material ripple.
+ * Draws a ripple background.
  */
-class RippleBackground {
+class RippleBackground extends RippleComponent {
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
 
-    private static final float GLOBAL_SPEED = 1.0f;
-    private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
-    private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
-    private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
-    private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
-    private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
-
-    private static final int ENTER_DURATION = 667;
-    private static final int ENTER_DURATION_FAST = 100;
-
-    // Hardware animators.
-    private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
-
-    private final RippleDrawable mOwner;
-
-    /** Bounds used for computing max radius. */
-    private final Rect mBounds;
-
-    /** ARGB color for drawing this ripple. */
-    private int mColor;
-
-    /** Maximum ripple radius. */
-    private float mOuterRadius;
-
-    /** Screen density used to adjust pixel-based velocities. */
-    private float mDensity;
+    private static final int OPACITY_ENTER_DURATION = 600;
+    private static final int OPACITY_ENTER_DURATION_FAST = 120;
+    private static final int OPACITY_EXIT_DURATION = 480;
 
     // Hardware rendering properties.
-    private CanvasProperty<Paint> mPropOuterPaint;
-    private CanvasProperty<Float> mPropOuterRadius;
-    private CanvasProperty<Float> mPropOuterX;
-    private CanvasProperty<Float> mPropOuterY;
-
-    // Software animators.
-    private ObjectAnimator mAnimOuterOpacity;
-
-    // Temporary paint used for creating canvas properties.
-    private Paint mTempPaint;
+    private CanvasProperty<Paint> mPropPaint;
+    private CanvasProperty<Float> mPropRadius;
+    private CanvasProperty<Float> mPropX;
+    private CanvasProperty<Float> mPropY;
 
     // Software rendering properties.
-    private float mOuterOpacity = 0;
-    private float mOuterX;
-    private float mOuterY;
+    private float mOpacity = 0;
 
-    /** Whether we should be drawing hardware animations. */
-    private boolean mHardwareAnimating;
-
-    /** Whether we can use hardware acceleration for the exit animation. */
-    private boolean mCanUseHardware;
-
-    /** Whether we have an explicit maximum radius. */
-    private boolean mHasMaxRadius;
-
-    private boolean mHasPendingHardwareExit;
-    private int mPendingOpacityDuration;
-    private int mPendingInflectionDuration;
-    private int mPendingInflectionOpacity;
-
-    /**
-     * Creates a new ripple.
-     */
     public RippleBackground(RippleDrawable owner, Rect bounds) {
-        mOwner = owner;
-        mBounds = bounds;
+        super(owner, bounds);
     }
 
-    public void setup(float maxRadius, float density) {
-        if (maxRadius >= 0) {
-            mHasMaxRadius = true;
-            mOuterRadius = maxRadius;
-        } else {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-        }
-
-        mOuterX = 0;
-        mOuterY = 0;
-        mDensity = density;
+    public boolean isVisible() {
+        return mOpacity > 0 || isHardwareAnimating();
     }
 
-    public void onHotspotBoundsChanged() {
-        if (!mHasMaxRadius) {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public void setOuterOpacity(float a) {
-        mOuterOpacity = a;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getOuterOpacity() {
-        return mOuterOpacity;
-    }
-
-    /**
-     * Draws the ripple centered at (0,0) using the specified paint.
-     */
-    public boolean draw(Canvas c, Paint p) {
-        mColor = p.getColor();
-
-        final boolean canUseHardware = c.isHardwareAccelerated();
-        if (mCanUseHardware != canUseHardware && mCanUseHardware) {
-            // We've switched from hardware to non-hardware mode. Panic.
-            cancelHardwareAnimations(true);
-        }
-        mCanUseHardware = canUseHardware;
-
-        final boolean hasContent;
-        if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) {
-            hasContent = drawHardware((HardwareCanvas) c, p);
-        } else {
-            hasContent = drawSoftware(c, p);
-        }
-
-        return hasContent;
-    }
-
-    public boolean shouldDraw() {
-        return (mCanUseHardware && mHardwareAnimating) || (mOuterOpacity > 0 && mOuterRadius > 0);
-    }
-
-    private boolean drawHardware(HardwareCanvas c, Paint p) {
-        if (mHasPendingHardwareExit) {
-            cancelHardwareAnimations(false);
-            startPendingHardwareExit(c, p);
-        }
-
-        c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
-
-        return true;
-    }
-
-    private boolean drawSoftware(Canvas c, Paint p) {
+    @Override
+    protected boolean drawSoftware(Canvas c, Paint p) {
         boolean hasContent = false;
 
-        final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * mOuterOpacity + 0.5f);
-        final float radius = mOuterRadius;
-        if (alpha > 0 && radius > 0) {
+        final int origAlpha = p.getAlpha();
+        final int alpha = (int) (origAlpha * mOpacity + 0.5f);
+        if (alpha > 0) {
             p.setAlpha(alpha);
-            c.drawCircle(mOuterX, mOuterY, radius, p);
-            p.setAlpha(paintAlpha);
+            c.drawCircle(0, 0, mTargetRadius, p);
+            p.setAlpha(origAlpha);
             hasContent = true;
         }
 
         return hasContent;
     }
 
-    /**
-     * Returns the maximum bounds of the ripple relative to the ripple center.
-     */
-    public void getBounds(Rect bounds) {
-        final int outerX = (int) mOuterX;
-        final int outerY = (int) mOuterY;
-        final int r = (int) mOuterRadius + 1;
-        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+    @Override
+    protected boolean drawHardware(HardwareCanvas c) {
+        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+        return true;
     }
 
-    /**
-     * Starts the enter animation.
-     */
-    public void enter(boolean fast) {
-        cancel();
+    @Override
+    protected Animator createSoftwareEnter(boolean fast) {
+        // Linear enter based on current opacity.
+        final int maxDuration = fast ? OPACITY_ENTER_DURATION_FAST : OPACITY_ENTER_DURATION;
+        final int duration = (int) ((1 - mOpacity) * maxDuration);
 
-        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1);
         opacity.setAutoCancel(true);
-        opacity.setDuration(fast ? ENTER_DURATION_FAST : ENTER_DURATION);
+        opacity.setDuration(duration);
         opacity.setInterpolator(LINEAR_INTERPOLATOR);
 
-        mAnimOuterOpacity = opacity;
-
-        // Enter animations always run on the UI thread, since it's unlikely
-        // that anything interesting is happening until the user lifts their
-        // finger.
-        opacity.start();
+        return opacity;
     }
 
-    /**
-     * Starts the exit animation.
-     */
-    public void exit() {
-        cancel();
+    @Override
+    protected Animator createSoftwareExit() {
+        final AnimatorSet set = new AnimatorSet();
 
-        // Scale the outer max opacity and opacity velocity based
-        // on the size of the outer radius.
-        final int opacityDuration = (int) (1000 / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
-        final float outerSizeInfluence = MathUtils.constrain(
-                (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
-                / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
-        final float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN,
-                WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX, outerSizeInfluence);
+        // Linear exit after enter is completed.
+        final ObjectAnimator exit = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 0);
+        exit.setInterpolator(LINEAR_INTERPOLATOR);
+        exit.setDuration(OPACITY_EXIT_DURATION);
+        exit.setAutoCancel(true);
 
-        // Determine at what time the inner and outer opacity intersect.
-        // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
-        // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
-        final int inflectionDuration = Math.max(0, (int) (1000 * (1 - mOuterOpacity)
-                / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
-        final int inflectionOpacity = (int) (Color.alpha(mColor) * (mOuterOpacity
-                + inflectionDuration * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
+        final AnimatorSet.Builder builder = set.play(exit);
 
-        if (mCanUseHardware) {
-            createPendingHardwareExit(opacityDuration, inflectionDuration, inflectionOpacity);
-        } else {
-            exitSoftware(opacityDuration, inflectionDuration, inflectionOpacity);
+        // Linear "fast" enter based on current opacity.
+        final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
+        if (fastEnterDuration > 0) {
+            final ObjectAnimator enter = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 1);
+            enter.setInterpolator(LINEAR_INTERPOLATOR);
+            enter.setDuration(fastEnterDuration);
+            enter.setAutoCancel(true);
+
+            builder.after(enter);
+        }
+
+        return set;
+    }
+
+    @Override
+    protected RenderNodeAnimatorSet createHardwareExit(Paint p) {
+        final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet();
+
+        final int targetAlpha = p.getAlpha();
+        final int currentAlpha = (int) (mOpacity * targetAlpha + 0.5f);
+        p.setAlpha(currentAlpha);
+
+        mPropPaint = CanvasProperty.createPaint(p);
+        mPropRadius = CanvasProperty.createFloat(mTargetRadius);
+        mPropX = CanvasProperty.createFloat(0);
+        mPropY = CanvasProperty.createFloat(0);
+
+        // Linear "fast" enter based on current opacity.
+        final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
+        if (fastEnterDuration > 0) {
+            final RenderNodeAnimator enter = new RenderNodeAnimator(
+                    mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha);
+            enter.setInterpolator(LINEAR_INTERPOLATOR);
+            enter.setDuration(fastEnterDuration);
+            set.add(enter);
+        }
+
+        // Linear exit after enter is completed.
+        final RenderNodeAnimator exit = new RenderNodeAnimator(
+                mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+        exit.setInterpolator(LINEAR_INTERPOLATOR);
+        exit.setDuration(OPACITY_EXIT_DURATION);
+        exit.setStartDelay(fastEnterDuration);
+        set.add(exit);
+
+        return set;
+    }
+
+    @Override
+    protected void jumpValuesToExit() {
+        mOpacity = 0;
+    }
+
+    private static abstract class BackgroundProperty extends FloatProperty<RippleBackground> {
+        public BackgroundProperty(String name) {
+            super(name);
         }
     }
 
-    private void createPendingHardwareExit(
-            int opacityDuration, int inflectionDuration, int inflectionOpacity) {
-        mHasPendingHardwareExit = true;
-        mPendingOpacityDuration = opacityDuration;
-        mPendingInflectionDuration = inflectionDuration;
-        mPendingInflectionOpacity = inflectionOpacity;
-
-        // The animation will start on the next draw().
-        invalidateSelf();
-    }
-
-    private void startPendingHardwareExit(HardwareCanvas c, Paint p) {
-        mHasPendingHardwareExit = false;
-
-        final int opacityDuration = mPendingOpacityDuration;
-        final int inflectionDuration = mPendingInflectionDuration;
-        final int inflectionOpacity = mPendingInflectionOpacity;
-
-        final Paint outerPaint = getTempPaint(p);
-        outerPaint.setAlpha((int) (outerPaint.getAlpha() * mOuterOpacity + 0.5f));
-        mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
-        mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
-        mPropOuterX = CanvasProperty.createFloat(mOuterX);
-        mPropOuterY = CanvasProperty.createFloat(mOuterY);
-
-        final RenderNodeAnimator outerOpacityAnim;
-        if (inflectionDuration > 0) {
-            // Outer opacity continues to increase for a bit.
-            outerOpacityAnim = new RenderNodeAnimator(mPropOuterPaint,
-                    RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
-            outerOpacityAnim.setDuration(inflectionDuration);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-            // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - inflectionDuration;
-            if (outerDuration > 0) {
-                final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator(
-                        mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
-                outerFadeOutAnim.setDuration(outerDuration);
-                outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
-                outerFadeOutAnim.setStartDelay(inflectionDuration);
-                outerFadeOutAnim.setStartValue(inflectionOpacity);
-                outerFadeOutAnim.addListener(mAnimationListener);
-                outerFadeOutAnim.setTarget(c);
-                outerFadeOutAnim.start();
-
-                mRunningAnimations.add(outerFadeOutAnim);
-            } else {
-                outerOpacityAnim.addListener(mAnimationListener);
-            }
-        } else {
-            outerOpacityAnim = new RenderNodeAnimator(
-                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-            outerOpacityAnim.setDuration(opacityDuration);
-            outerOpacityAnim.addListener(mAnimationListener);
-        }
-
-        outerOpacityAnim.setTarget(c);
-        outerOpacityAnim.start();
-
-        mRunningAnimations.add(outerOpacityAnim);
-
-        mHardwareAnimating = true;
-
-        // Set up the software values to match the hardware end values.
-        mOuterOpacity = 0;
-    }
-
-    /**
-     * Jump all animations to their end state. The caller is responsible for
-     * removing the ripple from the list of animating ripples.
-     */
-    public void jump() {
-        endSoftwareAnimations();
-        cancelHardwareAnimations(true);
-    }
-
-    private void endSoftwareAnimations() {
-        if (mAnimOuterOpacity != null) {
-            mAnimOuterOpacity.end();
-            mAnimOuterOpacity = null;
-        }
-    }
-
-    private Paint getTempPaint(Paint original) {
-        if (mTempPaint == null) {
-            mTempPaint = new Paint();
-        }
-        mTempPaint.set(original);
-        return mTempPaint;
-    }
-
-    private void exitSoftware(int opacityDuration, int inflectionDuration, int inflectionOpacity) {
-        final ObjectAnimator outerOpacityAnim;
-        if (inflectionDuration > 0) {
-            // Outer opacity continues to increase for a bit.
-            outerOpacityAnim = ObjectAnimator.ofFloat(this,
-                    "outerOpacity", inflectionOpacity / 255.0f);
-            outerOpacityAnim.setAutoCancel(true);
-            outerOpacityAnim.setDuration(inflectionDuration);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-            // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - inflectionDuration;
-            if (outerDuration > 0) {
-                outerOpacityAnim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        final ObjectAnimator outerFadeOutAnim = ObjectAnimator.ofFloat(
-                                RippleBackground.this, "outerOpacity", 0);
-                        outerFadeOutAnim.setAutoCancel(true);
-                        outerFadeOutAnim.setDuration(outerDuration);
-                        outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
-                        outerFadeOutAnim.addListener(mAnimationListener);
-
-                        mAnimOuterOpacity = outerFadeOutAnim;
-
-                        outerFadeOutAnim.start();
-                    }
-
-                    @Override
-                    public void onAnimationCancel(Animator animation) {
-                        animation.removeListener(this);
-                    }
-                });
-            } else {
-                outerOpacityAnim.addListener(mAnimationListener);
-            }
-        } else {
-            outerOpacityAnim = ObjectAnimator.ofFloat(this, "outerOpacity", 0);
-            outerOpacityAnim.setAutoCancel(true);
-            outerOpacityAnim.setDuration(opacityDuration);
-            outerOpacityAnim.addListener(mAnimationListener);
-        }
-
-        mAnimOuterOpacity = outerOpacityAnim;
-
-        outerOpacityAnim.start();
-    }
-
-    /**
-     * Cancel all animations. The caller is responsible for removing
-     * the ripple from the list of animating ripples.
-     */
-    public void cancel() {
-        cancelSoftwareAnimations();
-        cancelHardwareAnimations(false);
-    }
-
-    private void cancelSoftwareAnimations() {
-        if (mAnimOuterOpacity != null) {
-            mAnimOuterOpacity.cancel();
-            mAnimOuterOpacity = null;
-        }
-    }
-
-    /**
-     * Cancels any running hardware animations.
-     */
-    private void cancelHardwareAnimations(boolean jumpToEnd) {
-        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
-        final int N = runningAnimations.size();
-        for (int i = 0; i < N; i++) {
-            if (jumpToEnd) {
-                runningAnimations.get(i).end();
-            } else {
-                runningAnimations.get(i).cancel();
-            }
-        }
-        runningAnimations.clear();
-
-        if (mHasPendingHardwareExit) {
-            // If we had a pending hardware exit, jump to the end state.
-            mHasPendingHardwareExit = false;
-
-            if (jumpToEnd) {
-                mOuterOpacity = 0;
-            }
-        }
-
-        mHardwareAnimating = false;
-    }
-
-    private void invalidateSelf() {
-        mOwner.invalidateSelf();
-    }
-
-    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
+    private static final BackgroundProperty OPACITY = new BackgroundProperty("opacity") {
         @Override
-        public void onAnimationEnd(Animator animation) {
-            mHardwareAnimating = false;
+        public void setValue(RippleBackground object, float value) {
+            object.mOpacity = value;
+            object.invalidateSelf();
+        }
+
+        @Override
+        public Float get(RippleBackground object) {
+            return object.mOpacity;
         }
     };
 }
diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
new file mode 100644
index 0000000..79407f7
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -0,0 +1,326 @@
+/*
+ * 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.graphics.drawable;
+
+import android.animation.Animator;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+
+import java.util.ArrayList;
+
+/**
+ * Abstract class that handles hardware/software hand-off and lifecycle for
+ * animated ripple foreground and background components.
+ */
+abstract class RippleComponent {
+    private final RippleDrawable mOwner;
+
+    /** Bounds used for computing max radius. May be modified by the owner. */
+    protected final Rect mBounds;
+
+    /** Whether we can use hardware acceleration for the exit animation. */
+    private boolean mHasHardwareCanvas;
+
+    private boolean mHasPendingHardwareAnimator;
+    private RenderNodeAnimatorSet mHardwareAnimator;
+
+    private Animator mSoftwareAnimator;
+
+    /** Whether we have an explicit maximum radius. */
+    private boolean mHasMaxRadius;
+
+    /** How big this ripple should be when fully entered. */
+    protected float mTargetRadius;
+
+    /** Screen density used to adjust pixel-based constants. */
+    protected float mDensity;
+
+    public RippleComponent(RippleDrawable owner, Rect bounds) {
+        mOwner = owner;
+        mBounds = bounds;
+    }
+
+    public final void setup(float maxRadius, float density) {
+        if (maxRadius >= 0) {
+            mHasMaxRadius = true;
+            mTargetRadius = maxRadius;
+        } else {
+            final float halfWidth = mBounds.width() / 2.0f;
+            final float halfHeight = mBounds.height() / 2.0f;
+            mTargetRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+        }
+
+        mDensity = density;
+
+        onTargetRadiusChanged(mTargetRadius);
+    }
+
+    /**
+     * Starts a ripple enter animation.
+     *
+     * @param fast whether the ripple should enter quickly
+     */
+    public final void enter(boolean fast) {
+        cancel();
+
+        mSoftwareAnimator = createSoftwareEnter(fast);
+
+        if (mSoftwareAnimator != null) {
+            mSoftwareAnimator.start();
+        }
+    }
+
+    /**
+     * Starts a ripple exit animation.
+     */
+    public final void exit() {
+        cancel();
+
+        if (mHasHardwareCanvas) {
+            // We don't have access to a canvas here, but we expect one on the
+            // next frame. We'll start the render thread animation then.
+            mHasPendingHardwareAnimator = true;
+
+            // Request another frame.
+            invalidateSelf();
+        } else {
+            mSoftwareAnimator = createSoftwareExit();
+            mSoftwareAnimator.start();
+        }
+    }
+
+    /**
+     * Cancels all animations. Software animation values are left in the
+     * current state, while hardware animation values jump to the end state.
+     */
+    public void cancel() {
+        cancelSoftwareAnimations();
+        endHardwareAnimations();
+    }
+
+    /**
+     * Ends all animations, jumping values to the end state.
+     */
+    public void end() {
+        endSoftwareAnimations();
+        endHardwareAnimations();
+    }
+
+    /**
+     * Draws the ripple to the canvas, inheriting the paint's color and alpha
+     * properties.
+     *
+     * @param c the canvas to which the ripple should be drawn
+     * @param p the paint used to draw the ripple
+     * @return {@code true} if something was drawn, {@code false} otherwise
+     */
+    public boolean draw(Canvas c, Paint p) {
+        final boolean hasHardwareCanvas = c.isHardwareAccelerated()
+                && c instanceof HardwareCanvas;
+        if (mHasHardwareCanvas != hasHardwareCanvas) {
+            mHasHardwareCanvas = hasHardwareCanvas;
+
+            if (!hasHardwareCanvas) {
+                // We've switched from hardware to non-hardware mode. Panic.
+                endHardwareAnimations();
+            }
+        }
+
+        if (hasHardwareCanvas) {
+            final HardwareCanvas hw = (HardwareCanvas) c;
+            startPendingAnimation(hw, p);
+
+            if (mHardwareAnimator != null) {
+                return drawHardware(hw);
+            }
+        }
+
+        return drawSoftware(c, p);
+    }
+
+    /**
+     * Populates {@code bounds} with the maximum drawing bounds of the ripple
+     * relative to its center. The resulting bounds should be translated into
+     * parent drawable coordinates before use.
+     *
+     * @param bounds the rect to populate with drawing bounds
+     */
+    public void getBounds(Rect bounds) {
+        final int r = (int) Math.ceil(mTargetRadius);
+        bounds.set(-r, -r, r, r);
+    }
+
+    /**
+     * Starts the pending hardware animation, if available.
+     *
+     * @param hw hardware canvas on which the animation should draw
+     * @param p paint whose properties the hardware canvas should use
+     */
+    private void startPendingAnimation(HardwareCanvas hw, Paint p) {
+        if (mHasPendingHardwareAnimator) {
+            mHasPendingHardwareAnimator = false;
+
+            mHardwareAnimator = createHardwareExit(new Paint(p));
+            mHardwareAnimator.start(hw);
+
+            // Preemptively jump the software values to the end state now that
+            // the hardware exit has read whatever values it needs.
+            jumpValuesToExit();
+        }
+    }
+
+    /**
+     * Cancels any current software animations, leaving the values in their
+     * current state.
+     */
+    private void cancelSoftwareAnimations() {
+        if (mSoftwareAnimator != null) {
+            mSoftwareAnimator.cancel();
+        }
+    }
+
+    /**
+     * Ends any current software animations, jumping the values to their end
+     * state.
+     */
+    private void endSoftwareAnimations() {
+        if (mSoftwareAnimator != null) {
+            mSoftwareAnimator.end();
+        }
+    }
+
+    /**
+     * Ends any pending or current hardware animations.
+     * <p>
+     * Hardware animations can't synchronize values back to the software
+     * thread, so there is no "cancel" equivalent.
+     */
+    private void endHardwareAnimations() {
+        if (mHardwareAnimator != null) {
+            mHardwareAnimator.end();
+            mHardwareAnimator = null;
+        }
+
+        if (mHasPendingHardwareAnimator) {
+            mHasPendingHardwareAnimator = false;
+        }
+    }
+
+    protected final void invalidateSelf() {
+        mOwner.invalidateSelf();
+    }
+
+    protected final boolean isHardwareAnimating() {
+        return mHardwareAnimator != null && mHardwareAnimator.isRunning()
+                || mHasPendingHardwareAnimator;
+    }
+
+    protected final void onHotspotBoundsChanged() {
+        if (!mHasMaxRadius) {
+            final float halfWidth = mBounds.width() / 2.0f;
+            final float halfHeight = mBounds.height() / 2.0f;
+            final float targetRadius = (float) Math.sqrt(halfWidth * halfWidth
+                    + halfHeight * halfHeight);
+
+            onTargetRadiusChanged(targetRadius);
+        }
+    }
+
+    /**
+     * Called when the target radius changes.
+     *
+     * @param targetRadius the new target radius
+     */
+    protected void onTargetRadiusChanged(float targetRadius) {
+        // Stub.
+    }
+
+    protected abstract Animator createSoftwareEnter(boolean fast);
+
+    protected abstract Animator createSoftwareExit();
+
+    protected abstract RenderNodeAnimatorSet createHardwareExit(Paint p);
+
+    protected abstract boolean drawHardware(HardwareCanvas c);
+
+    protected abstract boolean drawSoftware(Canvas c, Paint p);
+
+    /**
+     * Called when the hardware exit is cancelled. Jumps software values to end
+     * state to ensure that software and hardware values are synchronized.
+     */
+    protected abstract void jumpValuesToExit();
+
+    public static class RenderNodeAnimatorSet {
+        private final ArrayList<RenderNodeAnimator> mAnimators = new ArrayList<>();
+
+        public void add(RenderNodeAnimator anim) {
+            mAnimators.add(anim);
+        }
+
+        public void clear() {
+            mAnimators.clear();
+        }
+
+        public void start(HardwareCanvas target) {
+            if (target == null) {
+                throw new IllegalArgumentException("Hardware canvas must be non-null");
+            }
+
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                anim.setTarget(target);
+                anim.start();
+            }
+        }
+
+        public void cancel() {
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                anim.cancel();
+            }
+        }
+
+        public void end() {
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                anim.end();
+            }
+        }
+
+        public boolean isRunning() {
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                if (anim.isRunning()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index b028eeb..66160c0 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -137,7 +137,7 @@
     private boolean mBackgroundActive;
 
     /** The current ripple. May be actively animating or pending entry. */
-    private Ripple mRipple;
+    private RippleForeground mRipple;
 
     /** Whether we expect to draw a ripple when visible. */
     private boolean mRippleActive;
@@ -151,7 +151,7 @@
      * Lazily-created array of actively animating ripples. Inactive ripples are
      * pruned during draw(). The locations of these will not change.
      */
-    private Ripple[] mExitingRipples;
+    private RippleForeground[] mExitingRipples;
     private int mExitingRipplesCount = 0;
 
     /** Paint used to control appearance of ripples. */
@@ -204,11 +204,11 @@
         super.jumpToCurrentState();
 
         if (mRipple != null) {
-            mRipple.jump();
+            mRipple.end();
         }
 
         if (mBackground != null) {
-            mBackground.jump();
+            mBackground.end();
         }
 
         cancelExitingRipples();
@@ -219,10 +219,13 @@
         boolean needsDraw = false;
 
         final int count = mExitingRipplesCount;
-        final Ripple[] ripples = mExitingRipples;
+        final RippleForeground[] ripples = mExitingRipples;
         for (int i = 0; i < count; i++) {
+            // If the ripple is animating on the hardware thread, we'll need to
+            // draw an additional frame after canceling to restore the software
+            // drawing path.
             needsDraw |= ripples[i].isHardwareAnimating();
-            ripples[i].cancel();
+            ripples[i].end();
         }
 
         if (ripples != null) {
@@ -264,11 +267,9 @@
         for (int state : stateSet) {
             if (state == R.attr.state_enabled) {
                 enabled = true;
-            }
-            if (state == R.attr.state_focused) {
+            } else if (state == R.attr.state_focused) {
                 focused = true;
-            }
-            if (state == R.attr.state_pressed) {
+            } else if (state == R.attr.state_pressed) {
                 pressed = true;
             }
         }
@@ -563,11 +564,13 @@
                 x = mHotspotBounds.exactCenterX();
                 y = mHotspotBounds.exactCenterY();
             }
-            mRipple = new Ripple(this, mHotspotBounds, x, y);
+
+            final boolean isBounded = !isProjected();
+            mRipple = new RippleForeground(this, mHotspotBounds, x, y, isBounded);
         }
 
         mRipple.setup(mState.mMaxRadius, mDensity);
-        mRipple.enter();
+        mRipple.enter(false);
     }
 
     /**
@@ -577,7 +580,7 @@
     private void tryRippleExit() {
         if (mRipple != null) {
             if (mExitingRipples == null) {
-                mExitingRipples = new Ripple[MAX_RIPPLES];
+                mExitingRipples = new RippleForeground[MAX_RIPPLES];
             }
             mExitingRipples[mExitingRipplesCount++] = mRipple;
             mRipple.exit();
@@ -591,13 +594,13 @@
      */
     private void clearHotspots() {
         if (mRipple != null) {
-            mRipple.cancel();
+            mRipple.end();
             mRipple = null;
             mRippleActive = false;
         }
 
         if (mBackground != null) {
-            mBackground.cancel();
+            mBackground.end();
             mBackground = null;
             mBackgroundActive = false;
         }
@@ -624,7 +627,7 @@
      */
     private void onHotspotBoundsChanged() {
         final int count = mExitingRipplesCount;
-        final Ripple[] ripples = mExitingRipples;
+        final RippleForeground[] ripples = mExitingRipples;
         for (int i = 0; i < count; i++) {
             ripples[i].onHotspotBoundsChanged();
         }
@@ -662,6 +665,8 @@
      */
     @Override
     public void draw(@NonNull Canvas canvas) {
+        pruneRipples();
+
         // Clip to the dirty bounds, which will be the drawable bounds if we
         // have a mask or content and the ripple bounds if we're projecting.
         final Rect bounds = getDirtyBounds();
@@ -682,6 +687,26 @@
         mHasValidMask = false;
     }
 
+    private void pruneRipples() {
+        int remaining = 0;
+
+        // Move remaining entries into pruned spaces.
+        final RippleForeground[] ripples = mExitingRipples;
+        final int count = mExitingRipplesCount;
+        for (int i = 0; i < count; i++) {
+            if (!ripples[i].hasFinishedExit()) {
+                ripples[remaining++] = ripples[i];
+            }
+        }
+
+        // Null out the remaining entries.
+        for (int i = remaining; i < count; i++) {
+            ripples[i] = null;
+        }
+
+        mExitingRipplesCount = remaining;
+    }
+
     /**
      * @return whether we need to use a mask
      */
@@ -747,7 +772,7 @@
 
     private int getMaskType() {
         if (mRipple == null && mExitingRipplesCount <= 0
-                && (mBackground == null || !mBackground.shouldDraw())) {
+                && (mBackground == null || !mBackground.isVisible())) {
             // We might need a mask later.
             return MASK_UNKNOWN;
         }
@@ -774,36 +799,6 @@
         return MASK_NONE;
     }
 
-    /**
-     * Removes a ripple from the exiting ripple list.
-     *
-     * @param ripple the ripple to remove
-     */
-    void removeRipple(Ripple ripple) {
-        // Ripple ripple ripple ripple. Ripple ripple.
-        final Ripple[] ripples = mExitingRipples;
-        final int count = mExitingRipplesCount;
-        final int index = getRippleIndex(ripple);
-        if (index >= 0) {
-            System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1));
-            ripples[count - 1] = null;
-            mExitingRipplesCount--;
-
-            invalidateSelf();
-        }
-    }
-
-    private int getRippleIndex(Ripple ripple) {
-        final Ripple[] ripples = mExitingRipples;
-        final int count = mExitingRipplesCount;
-        for (int i = 0; i < count; i++) {
-            if (ripples[i] == ripple) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
     private void drawContent(Canvas canvas) {
         // Draw everything except the mask.
         final ChildDrawable[] array = mLayerState.mChildren;
@@ -816,10 +811,10 @@
     }
 
     private void drawBackgroundAndRipples(Canvas canvas) {
-        final Ripple active = mRipple;
+        final RippleForeground active = mRipple;
         final RippleBackground background = mBackground;
         final int count = mExitingRipplesCount;
-        if (active == null && count <= 0 && (background == null || !background.shouldDraw())) {
+        if (active == null && count <= 0 && (background == null || !background.isVisible())) {
             // Move along, nothing to draw here.
             return;
         }
@@ -859,12 +854,12 @@
             p.setShader(null);
         }
 
-        if (background != null && background.shouldDraw()) {
+        if (background != null && background.isVisible()) {
             background.draw(canvas, p);
         }
 
         if (count > 0) {
-            final Ripple[] ripples = mExitingRipples;
+            final RippleForeground[] ripples = mExitingRipples;
             for (int i = 0; i < count; i++) {
                 ripples[i].draw(canvas, p);
             }
@@ -902,7 +897,7 @@
             final int cY = (int) mHotspotBounds.exactCenterY();
             final Rect rippleBounds = mTempRect;
 
-            final Ripple[] activeRipples = mExitingRipples;
+            final RippleForeground[] activeRipples = mExitingRipples;
             final int N = mExitingRipplesCount;
             for (int i = 0; i < N; i++) {
                 activeRipples[i].getBounds(rippleBounds);
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
new file mode 100644
index 0000000..334122d
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -0,0 +1,434 @@
+/*
+ * 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.graphics.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.FloatProperty;
+import android.util.MathUtils;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Draws a ripple foreground.
+ */
+class RippleForeground extends RippleComponent {
+    private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
+    private static final TimeInterpolator DECELERATE_INTERPOLATOR = new LogDecelerateInterpolator(
+            400f, 1.4f, 0);
+
+    // Pixel-based accelerations and velocities.
+    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024;
+    private static final float WAVE_TOUCH_UP_ACCELERATION = 3400;
+    private static final float WAVE_OPACITY_DECAY_VELOCITY = 3;
+
+    // Bounded ripple animation properties.
+    private static final int BOUNDED_ORIGIN_EXIT_DURATION = 300;
+    private static final int BOUNDED_RADIUS_EXIT_DURATION = 800;
+    private static final int BOUNDED_OPACITY_EXIT_DURATION = 400;
+    private static final float MAX_BOUNDED_RADIUS = 350;
+
+    private static final int RIPPLE_ENTER_DELAY = 80;
+    private static final int OPACITY_ENTER_DURATION_FAST = 120;
+
+    // Parent-relative values for starting position.
+    private float mStartingX;
+    private float mStartingY;
+    private float mClampedStartingX;
+    private float mClampedStartingY;
+
+    // Hardware rendering properties.
+    private CanvasProperty<Paint> mPropPaint;
+    private CanvasProperty<Float> mPropRadius;
+    private CanvasProperty<Float> mPropX;
+    private CanvasProperty<Float> mPropY;
+
+    // Target values for tween animations.
+    private float mTargetX = 0;
+    private float mTargetY = 0;
+
+    /** Ripple target radius used when bounded. Not used for clamping. */
+    private float mBoundedRadius = 0;
+
+    // Software rendering properties.
+    private float mOpacity = 1;
+
+    // Values used to tween between the start and end positions.
+    private float mTweenRadius = 0;
+    private float mTweenX = 0;
+    private float mTweenY = 0;
+
+    /** Whether this ripple is bounded. */
+    private boolean mIsBounded;
+
+    /** Whether this ripple has finished its exit animation. */
+    private boolean mHasFinishedExit;
+
+    public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY,
+            boolean isBounded) {
+        super(owner, bounds);
+
+        mIsBounded = isBounded;
+        mStartingX = startingX;
+        mStartingY = startingY;
+
+        if (isBounded) {
+            mBoundedRadius = MAX_BOUNDED_RADIUS * 0.9f
+                    + (float) (MAX_BOUNDED_RADIUS * Math.random() * 0.1);
+        } else {
+            mBoundedRadius = 0;
+        }
+    }
+
+    @Override
+    protected void onTargetRadiusChanged(float targetRadius) {
+        clampStartingPosition();
+    }
+
+    @Override
+    protected boolean drawSoftware(Canvas c, Paint p) {
+        boolean hasContent = false;
+
+        final int origAlpha = p.getAlpha();
+        final int alpha = (int) (origAlpha * mOpacity + 0.5f);
+        final float radius = getCurrentRadius();
+        if (alpha > 0 && radius > 0) {
+            final float x = getCurrentX();
+            final float y = getCurrentY();
+            p.setAlpha(alpha);
+            c.drawCircle(x, y, radius, p);
+            p.setAlpha(origAlpha);
+            hasContent = true;
+        }
+
+        return hasContent;
+    }
+
+    @Override
+    protected boolean drawHardware(HardwareCanvas c) {
+        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+        return true;
+    }
+
+    /**
+     * Returns the maximum bounds of the ripple relative to the ripple center.
+     */
+    public void getBounds(Rect bounds) {
+        final int outerX = (int) mTargetX;
+        final int outerY = (int) mTargetY;
+        final int r = (int) mTargetRadius + 1;
+        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+    }
+
+    /**
+     * Specifies the starting position relative to the drawable bounds. No-op if
+     * the ripple has already entered.
+     */
+    public void move(float x, float y) {
+        mStartingX = x;
+        mStartingY = y;
+
+        clampStartingPosition();
+    }
+
+    /**
+     * @return {@code true} if this ripple has finished its exit animation
+     */
+    public boolean hasFinishedExit() {
+        return mHasFinishedExit;
+    }
+
+    @Override
+    protected Animator createSoftwareEnter(boolean fast) {
+        // Bounded ripples don't have enter animations.
+        if (mIsBounded) {
+            return null;
+        }
+
+        final int duration = (int)
+                (1000 * Math.sqrt(mTargetRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
+
+        final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
+        tweenRadius.setAutoCancel(true);
+        tweenRadius.setDuration(duration);
+        tweenRadius.setInterpolator(LINEAR_INTERPOLATOR);
+        tweenRadius.setStartDelay(RIPPLE_ENTER_DELAY);
+
+        final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
+        tweenOrigin.setAutoCancel(true);
+        tweenOrigin.setDuration(duration);
+        tweenOrigin.setInterpolator(LINEAR_INTERPOLATOR);
+        tweenOrigin.setStartDelay(RIPPLE_ENTER_DELAY);
+
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(OPACITY_ENTER_DURATION_FAST);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+
+        final AnimatorSet set = new AnimatorSet();
+        set.play(tweenOrigin).with(tweenRadius).with(opacity);
+
+        return set;
+    }
+
+    private float getCurrentX() {
+        return MathUtils.lerp(mClampedStartingX - mBounds.exactCenterX(), mTargetX, mTweenX);
+    }
+
+    private float getCurrentY() {
+        return MathUtils.lerp(mClampedStartingY - mBounds.exactCenterY(), mTargetY, mTweenY);
+    }
+
+    private int getRadiusExitDuration() {
+        final float remainingRadius = mTargetRadius - getCurrentRadius();
+        return (int) (1000 * Math.sqrt(remainingRadius / (WAVE_TOUCH_UP_ACCELERATION
+                + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
+    }
+
+    private float getCurrentRadius() {
+        return MathUtils.lerp(0, mTargetRadius, mTweenRadius);
+    }
+
+    private int getOpacityExitDuration() {
+        return (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+    }
+
+    /**
+     * Compute target values that are dependent on bounding.
+     */
+    private void computeBoundedTargetValues() {
+        mTargetX = (mClampedStartingX - mBounds.exactCenterX()) * .7f;
+        mTargetY = (mClampedStartingY - mBounds.exactCenterY()) * .7f;
+        mTargetRadius = mBoundedRadius;
+    }
+
+    @Override
+    protected Animator createSoftwareExit() {
+        final int radiusDuration;
+        final int originDuration;
+        final int opacityDuration;
+        if (mIsBounded) {
+            computeBoundedTargetValues();
+
+            radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
+            originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
+            opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
+        } else {
+            radiusDuration = getRadiusExitDuration();
+            originDuration = radiusDuration;
+            opacityDuration = getOpacityExitDuration();
+        }
+
+        final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
+        tweenRadius.setAutoCancel(true);
+        tweenRadius.setDuration(radiusDuration);
+        tweenRadius.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
+        tweenOrigin.setAutoCancel(true);
+        tweenOrigin.setDuration(originDuration);
+        tweenOrigin.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 0);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(opacityDuration);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+
+        final AnimatorSet set = new AnimatorSet();
+        set.play(tweenOrigin).with(tweenRadius).with(opacity);
+        set.addListener(mAnimationListener);
+
+        return set;
+    }
+
+    @Override
+    protected RenderNodeAnimatorSet createHardwareExit(Paint p) {
+        final int radiusDuration;
+        final int originDuration;
+        final int opacityDuration;
+        if (mIsBounded) {
+            computeBoundedTargetValues();
+
+            radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
+            originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
+            opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
+        } else {
+            radiusDuration = getRadiusExitDuration();
+            originDuration = radiusDuration;
+            opacityDuration = getOpacityExitDuration();
+        }
+
+        final float startX = getCurrentX();
+        final float startY = getCurrentY();
+        final float startRadius = getCurrentRadius();
+
+        p.setAlpha((int) (p.getAlpha() * mOpacity + 0.5f));
+
+        mPropPaint = CanvasProperty.createPaint(p);
+        mPropRadius = CanvasProperty.createFloat(startRadius);
+        mPropX = CanvasProperty.createFloat(startX);
+        mPropY = CanvasProperty.createFloat(startY);
+
+        final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mTargetRadius);
+        radius.setDuration(radiusDuration);
+        radius.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mTargetX);
+        x.setDuration(originDuration);
+        x.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mTargetY);
+        y.setDuration(originDuration);
+        y.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+                RenderNodeAnimator.PAINT_ALPHA, 0);
+        opacity.setDuration(opacityDuration);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+        opacity.addListener(mAnimationListener);
+
+        final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet();
+        set.add(radius);
+        set.add(opacity);
+        set.add(x);
+        set.add(y);
+
+        return set;
+    }
+
+    @Override
+    protected void jumpValuesToExit() {
+        mOpacity = 0;
+        mTweenX = 1;
+        mTweenY = 1;
+        mTweenRadius = 1;
+    }
+
+    /**
+     * Clamps the starting position to fit within the ripple bounds.
+     */
+    private void clampStartingPosition() {
+        final float cX = mBounds.exactCenterX();
+        final float cY = mBounds.exactCenterY();
+        final float dX = mStartingX - cX;
+        final float dY = mStartingY - cY;
+        final float r = mTargetRadius;
+        if (dX * dX + dY * dY > r * r) {
+            // Point is outside the circle, clamp to the perimeter.
+            final double angle = Math.atan2(dY, dX);
+            mClampedStartingX = cX + (float) (Math.cos(angle) * r);
+            mClampedStartingY = cY + (float) (Math.sin(angle) * r);
+        } else {
+            mClampedStartingX = mStartingX;
+            mClampedStartingY = mStartingY;
+        }
+    }
+
+    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animator) {
+            mHasFinishedExit = true;
+        }
+    };
+
+    /**
+    * Interpolator with a smooth log deceleration.
+    */
+    private static final class LogDecelerateInterpolator implements TimeInterpolator {
+        private final float mBase;
+        private final float mDrift;
+        private final float mTimeScale;
+        private final float mOutputScale;
+
+        public LogDecelerateInterpolator(float base, float timeScale, float drift) {
+            mBase = base;
+            mDrift = drift;
+            mTimeScale = 1f / timeScale;
+
+            mOutputScale = 1f / computeLog(1f);
+        }
+
+        private float computeLog(float t) {
+            return 1f - (float) Math.pow(mBase, -t * mTimeScale) + (mDrift * t);
+        }
+
+        @Override
+        public float getInterpolation(float t) {
+            return computeLog(t) * mOutputScale;
+        }
+    }
+
+    /**
+     * Property for animating radius between its initial and target values.
+     */
+    private static final FloatProperty<RippleForeground> TWEEN_RADIUS =
+            new FloatProperty<RippleForeground>("tweenRadius") {
+        @Override
+        public void setValue(RippleForeground object, float value) {
+            object.mTweenRadius = value;
+            object.invalidateSelf();
+        }
+
+        @Override
+        public Float get(RippleForeground object) {
+            return object.mTweenRadius;
+        }
+    };
+
+    /**
+     * Property for animating origin between its initial and target values.
+     */
+    private static final FloatProperty<RippleForeground> TWEEN_ORIGIN =
+            new FloatProperty<RippleForeground>("tweenOrigin") {
+                @Override
+                public void setValue(RippleForeground object, float value) {
+                    object.mTweenX = value;
+                    object.mTweenY = value;
+                    object.invalidateSelf();
+                }
+
+                @Override
+                public Float get(RippleForeground object) {
+                    return object.mTweenX;
+                }
+            };
+
+    /**
+     * Property for animating opacity between 0 and its target value.
+     */
+    private static final FloatProperty<RippleForeground> OPACITY =
+            new FloatProperty<RippleForeground>("opacity") {
+        @Override
+        public void setValue(RippleForeground object, float value) {
+            object.mOpacity = value;
+            object.invalidateSelf();
+        }
+
+        @Override
+        public Float get(RippleForeground object) {
+            return object.mOpacity;
+        }
+    };
+}
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 79934da..b32dcc6 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -380,7 +380,7 @@
 
             final long transformPtr = (transform != null) ? transform.native_instance : 0;
 
-            nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft,
+            nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft,
                     contentTop, contentRight, contentBottom, transformPtr, renderMode);
         }
 
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index 53e8b49..a6836a8 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -26,6 +26,33 @@
 class Surface;
 class IGraphicBufferProducer;
 
+/**
+ * Enum mirroring the public API definitions for image and pixel formats.
+ * Some of these are hidden in the public API
+ *
+ * Keep up to date with android.graphics.ImageFormat and
+ * android.graphics.PixelFormat
+ */
+enum class PublicFormat {
+    UNKNOWN           = 0x0,
+    RGBA_8888         = 0x1,
+    RGBX_8888         = 0x2,
+    RGB_888           = 0x3,
+    RGB_565           = 0x4,
+    NV16              = 0x10,
+    NV21              = 0x11,
+    YUY2              = 0x14,
+    RAW_SENSOR        = 0x20,
+    YUV_420_888       = 0x23,
+    RAW10             = 0x25,
+    JPEG              = 0x100,
+    DEPTH_POINT_CLOUD = 0x101,
+    YV12              = 0x32315659,
+    Y8                = 0x20203859, // @hide
+    Y16               = 0x20363159, // @hide
+    DEPTH16           = 0x44363159
+};
+
 /* Gets the underlying ANativeWindow for a Surface. */
 extern sp<ANativeWindow> android_view_Surface_getNativeWindow(
         JNIEnv* env, jobject surfaceObj);
@@ -40,6 +67,21 @@
 extern jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
         const sp<IGraphicBufferProducer>& bufferProducer);
 
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * format */
+extern int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f);
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * dataspace */
+extern android_dataspace android_view_Surface_mapPublicFormatToHalDataspace(
+        PublicFormat f);
+
+/* Convert from HAL format, dataspace pair to
+ * android.graphics.ImageFormat/PixelFormat.
+ * For unknown/unspecified pairs, returns PublicFormat::UNKNOWN */
+extern PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat(
+        int format, android_dataspace dataSpace);
+
 } // namespace android
 
 #endif // _ANDROID_VIEW_SURFACE_H
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 6a59a13..6b8c780 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -109,6 +109,9 @@
         mSurfaceTexture->getTransformMatrix(transform);
         GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
 
+        LOG_ALWAYS_FATAL_IF(renderTarget != GL_TEXTURE_2D && renderTarget != GL_TEXTURE_EXTERNAL_OES,
+                "doUpdateTexImage target %x, 2d %x, EXT %x",
+                renderTarget, GL_TEXTURE_2D, GL_TEXTURE_EXTERNAL_OES);
         LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight,
                 !mBlend, forceFilter, renderTarget, transform);
     }
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 38d8e4a..82f2741 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -59,6 +59,10 @@
         if (texture.get() != mSurfaceTexture.get()) {
             mNeedsGLContextAttach = needsAttach;
             mSurfaceTexture = texture;
+
+            GLenum target = texture->getCurrentTextureTarget();
+            LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
+                    "set unsupported GLConsumer with target %x", target);
         }
     }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 71c1fc3..d313c18 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -216,7 +216,7 @@
     virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
             const float* verts, const float* tex, const int* colors,
             const uint16_t* indices, int indexCount, const SkPaint& paint) override
-        { LOG_ALWAYS_FATAL("DisplayListRenderer does not support drawVertices()"); }
+        { /* DisplayListRenderer does not support drawVertices(); ignore */ }
 
     // Bitmap-based
     virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override;
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 62da6e08..2c6f6c1 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -78,7 +78,7 @@
         // TODO: enforce mutual exclusion with restricted setters and/or unions
         struct Vertices {
             GLuint bufferObject;
-            VertexAttribFlags flags;
+            int attribFlags;
             const void* position;
             const void* texCoord;
             const void* color;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index f94dc38..0a46014 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -66,7 +66,7 @@
     mOutGlop->mesh.indices = { 0, nullptr };
     mOutGlop->mesh.vertices = {
             mRenderState.meshState().getUnitQuadVBO(),
-            VertexAttribFlags::kNone,
+            static_cast<int>(VertexAttribFlags::kNone),
             nullptr, nullptr, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = 4;
@@ -85,7 +85,7 @@
     mOutGlop->mesh.indices = { 0, nullptr };
     mOutGlop->mesh.vertices = {
             mRenderState.meshState().getUnitQuadVBO(),
-            VertexAttribFlags::kTextureCoord,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
             nullptr, (const void*) kMeshTextureOffset, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = 4;
@@ -105,7 +105,7 @@
     mOutGlop->mesh.indices = { 0, nullptr };
     mOutGlop->mesh.vertices = {
             0,
-            VertexAttribFlags::kTextureCoord,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
             &textureVertex[0].x, &textureVertex[0].u, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = 4;
@@ -119,7 +119,7 @@
     mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
     mOutGlop->mesh.vertices = {
             0,
-            VertexAttribFlags::kNone,
+            static_cast<int>(VertexAttribFlags::kNone),
             vertexData, nullptr, nullptr,
             kVertexStride };
     mOutGlop->mesh.elementCount = 6 * quadCount;
@@ -133,7 +133,7 @@
     mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
     mOutGlop->mesh.vertices = {
             0,
-            VertexAttribFlags::kTextureCoord,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
             &vertexData[0].x, &vertexData[0].u, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = elementCount;
@@ -147,7 +147,7 @@
     mOutGlop->mesh.indices = { 0, nullptr };
     mOutGlop->mesh.vertices = {
             0,
-            VertexAttribFlags::kTextureCoord,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
             &vertexData[0].x, &vertexData[0].u, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = elementCount;
@@ -161,7 +161,7 @@
     mOutGlop->mesh.indices = { 0, nullptr };
     mOutGlop->mesh.vertices = {
             0,
-            static_cast<VertexAttribFlags>(VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor),
+            VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor,
             &vertexData[0].x, &vertexData[0].u, &vertexData[0].r,
             kColorTextureVertexStride };
     mOutGlop->mesh.elementCount = elementCount;
@@ -180,7 +180,7 @@
     mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() };
     mOutGlop->mesh.vertices = {
             0,
-            alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone,
+            static_cast<int>(alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone),
             vertexBuffer.getBuffer(), nullptr, nullptr,
             alphaVertex ? kAlphaVertexStride : kVertexStride };
     mOutGlop->mesh.elementCount = indices
@@ -197,8 +197,8 @@
     mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
     mOutGlop->mesh.vertices = {
             mCaches.patchCache.getMeshBuffer(),
-            VertexAttribFlags::kTextureCoord,
-            (void*)patch.offset, (void*)patch.textureOffset, nullptr,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
+            (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = patch.indexCount;
     return *this;
@@ -208,7 +208,8 @@
 // Fill
 ////////////////////////////////////////////////////////////////////////////////
 
-void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode,
+void GlopBuilder::setFill(int color, float alphaScale,
+        SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
         const SkShader* shader, const SkColorFilter* colorFilter) {
     if (mode != SkXfermode::kClear_Mode) {
         float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
@@ -226,18 +227,17 @@
     } else {
         mOutGlop->fill.color = { 0, 0, 0, 1 };
     }
-    const bool SWAP_SRC_DST = false;
 
     mOutGlop->blend = { GL_ZERO, GL_ZERO };
     if (mOutGlop->fill.color.a < 1.0f
-            || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha)
+            || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha)
             || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
             || mOutGlop->roundRectClipState
             || PaintUtils::isBlendedShader(shader)
             || PaintUtils::isBlendedColorFilter(colorFilter)
             || mode != SkXfermode::kSrcOver_Mode) {
         if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) {
-            Blend::getFactors(mode, SWAP_SRC_DST,
+            Blend::getFactors(mode, modeUsage,
                     &mOutGlop->blend.src, &mOutGlop->blend.dst);
         } else {
             // These blend modes are not supported by OpenGL directly and have
@@ -247,11 +247,11 @@
             // back to the default SrcOver blend mode instead
             if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
                 mDescription.framebufferMode = mode;
-                mDescription.swapSrcDst = SWAP_SRC_DST;
+                mDescription.swapSrcDst = (modeUsage == Blend::ModeOrderSwap::Swap);
                 // blending in shader, don't enable
             } else {
                 // unsupported
-                Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+                Blend::getFactors(SkXfermode::kSrcOver_Mode, modeUsage,
                         &mOutGlop->blend.src, &mOutGlop->blend.dst);
             }
         }
@@ -317,17 +317,17 @@
             color |= 0x00FFFFFF;
             shader = nullptr;
         }
-        setFill(color, alphaScale, PaintUtils::getXfermode(paint->getXfermode()),
+        setFill(color, alphaScale,
+                PaintUtils::getXfermode(paint->getXfermode()), Blend::ModeOrderSwap::NoSwap,
                 shader, paint->getColorFilter());
     } else {
         mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
 
-        const bool SWAP_SRC_DST = false;
         if (alphaScale < 1.0f
-                || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha)
+                || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha)
                 || texture.blend
                 || mOutGlop->roundRectClipState) {
-            Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+            Blend::getFactors(SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
                     &mOutGlop->blend.src, &mOutGlop->blend.dst);
         } else {
             mOutGlop->blend = { GL_ZERO, GL_ZERO };
@@ -349,7 +349,8 @@
 
     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
-    setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+    setFill(paint.getColor(), alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
             paint.getShader(), paint.getColorFilter());
     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
     return *this;
@@ -363,7 +364,8 @@
     //specify invalid filter/clamp, since these are always static for PathTextures
     mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
-    setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+    setFill(paint.getColor(), alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
             paint.getShader(), paint.getColorFilter());
 
     mDescription.hasAlpha8Texture = true;
@@ -386,7 +388,8 @@
         shadowColor &= paint.getColor() | COLOR_BITMASK;
     }
 
-    setFill(shadowColor, alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+    setFill(shadowColor, alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
             paint.getShader(), paint.getColorFilter());
 
     mDescription.hasAlpha8Texture = true;
@@ -399,7 +402,8 @@
     REQUIRE_STAGES(kMeshStage);
 
     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
-    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, nullptr, nullptr);
+    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
+            nullptr, nullptr);
     return *this;
 }
 
@@ -408,12 +412,13 @@
     REQUIRE_STAGES(kMeshStage);
 
     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
-    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, nullptr, nullptr);
+    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, Blend::ModeOrderSwap::NoSwap,
+            nullptr, nullptr);
     return *this;
 }
 
 GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
-        float alpha, SkXfermode::Mode mode) {
+        float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage) {
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
@@ -421,7 +426,7 @@
             GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
     mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
 
-    setFill(SK_ColorWHITE, alpha, mode, nullptr, colorFilter);
+    setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
 
     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
     return *this;
@@ -435,7 +440,8 @@
             layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
     mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
 
-    setFill(SK_ColorWHITE, alpha, layer.getMode(), nullptr, layer.getColorFilter());
+    setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
+            nullptr, layer.getColorFilter());
 
     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
     mDescription.hasTextureTransform = true;
@@ -518,6 +524,7 @@
     }
 
     mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+    mOutGlop->bounds = source;
     mOutGlop->bounds.translate(offsetX, offsetY);
     return *this;
 }
@@ -539,12 +546,25 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 void verify(const ProgramDescription& description, const Glop& glop) {
-    bool hasTexture = glop.fill.texture.texture != nullptr;
-    LOG_ALWAYS_FATAL_IF(description.hasTexture && description.hasExternalTexture);
-    LOG_ALWAYS_FATAL_IF((description.hasTexture || description.hasExternalTexture )!= hasTexture);
-    LOG_ALWAYS_FATAL_IF((glop.mesh.vertices.flags & VertexAttribFlags::kTextureCoord) != hasTexture);
+    if (glop.fill.texture.texture != nullptr) {
+        LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture)
+                        || (!description.hasTexture && !description.hasExternalTexture)
+                        || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) == 0)),
+                "Texture %p, hT%d, hET %d, attribFlags %x",
+                glop.fill.texture.texture,
+                description.hasTexture, description.hasExternalTexture,
+                glop.mesh.vertices.attribFlags);
+    } else {
+        LOG_ALWAYS_FATAL_IF((description.hasTexture
+                        || description.hasExternalTexture
+                        || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) != 0)),
+                "No texture, hT%d, hET %d, attribFlags %x",
+                description.hasTexture, description.hasExternalTexture,
+                glop.mesh.vertices.attribFlags);
+    }
 
-    if ((glop.mesh.vertices.flags & VertexAttribFlags::kAlpha) && glop.mesh.vertices.bufferObject) {
+    if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kAlpha)
+            && glop.mesh.vertices.bufferObject) {
         LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
     }
 
@@ -555,12 +575,16 @@
 
 void GlopBuilder::build() {
     REQUIRE_STAGES(kAllStages);
-    if (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kTextureCoord) {
-        mDescription.hasTexture = mOutGlop->fill.texture.target == GL_TEXTURE_2D;
-        mDescription.hasExternalTexture = mOutGlop->fill.texture.target == GL_TEXTURE_EXTERNAL_OES;
+    if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) {
+        if (mOutGlop->fill.texture.target == GL_TEXTURE_2D) {
+            mDescription.hasTexture = true;
+        } else {
+            mDescription.hasExternalTexture = true;
+        }
+
     }
-    mDescription.hasColors = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kColor;
-    mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha;
+    mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kColor;
+    mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha;
 
     // serialize shader info into ShaderData
     GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 74d4889..b335a2c 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -18,6 +18,7 @@
 
 #include "OpenGLRenderer.h"
 #include "Program.h"
+#include "renderstate/Blend.h"
 #include "utils/Macros.h"
 
 class SkPaint;
@@ -65,7 +66,7 @@
     GlopBuilder& setFillBlack();
     GlopBuilder& setFillClear();
     GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
-            float alpha, SkXfermode::Mode mode);
+            float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage);
     GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
 
     GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
@@ -94,7 +95,8 @@
 
     void build();
 private:
-    void setFill(int color, float alphaScale, SkXfermode::Mode mode,
+    void setFill(int color, float alphaScale,
+            SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
             const SkShader* shader, const SkColorFilter* colorFilter);
 
     enum StageFlags {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index d0ea3a6..46b0945 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -15,6 +15,7 @@
  */
 #include "JankTracker.h"
 
+#include <algorithm>
 #include <cstdio>
 #include <inttypes.h>
 
@@ -95,7 +96,12 @@
     // Fast-path for jank-free frames
     int64_t totalDuration =
             frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync];
+    uint32_t framebucket = std::min(
+            static_cast<typeof sizeof(mFrameCounts)>(ns2ms(totalDuration)),
+            sizeof(mFrameCounts) / sizeof(mFrameCounts[0]));
+    // Keep the fast path as fast as possible.
     if (CC_LIKELY(totalDuration < mFrameInterval)) {
+        mFrameCounts[framebucket]++;
         return;
     }
 
@@ -103,6 +109,7 @@
         return;
     }
 
+    mFrameCounts[framebucket]++;
     mJankFrameCount++;
 
     for (int i = 0; i < NUM_BUCKETS; i++) {
@@ -119,6 +126,9 @@
     fprintf(file, "\n  Total frames rendered: %u", mTotalFrameCount);
     fprintf(file, "\n  Janky frames: %u (%.2f%%)", mJankFrameCount,
             (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
+    fprintf(file, "\n  90th percentile: %ums", findPercentile(90));
+    fprintf(file, "\n  95th percentile: %ums", findPercentile(95));
+    fprintf(file, "\n  99th percentile: %ums", findPercentile(99));
     for (int i = 0; i < NUM_BUCKETS; i++) {
         fprintf(file, "\n   Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count);
     }
@@ -127,10 +137,23 @@
 }
 
 void JankTracker::reset() {
-    memset(mBuckets, 0, sizeof(JankBucket) * NUM_BUCKETS);
+    memset(mBuckets, 0, sizeof(mBuckets));
+    memset(mFrameCounts, 0, sizeof(mFrameCounts));
     mTotalFrameCount = 0;
     mJankFrameCount = 0;
 }
 
+uint32_t JankTracker::findPercentile(int percentile) {
+    int pos = percentile * mTotalFrameCount / 100;
+    int remaining = mTotalFrameCount - pos;
+    for (int i = sizeof(mFrameCounts) / sizeof(mFrameCounts[0]) - 1; i >= 0; i--) {
+        remaining -= mFrameCounts[i];
+        if (remaining <= 0) {
+            return i;
+        }
+    }
+    return 0;
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index aa554cd..3d4929b 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -54,8 +54,11 @@
     void reset();
 
 private:
+    uint32_t findPercentile(int p);
+
     JankBucket mBuckets[NUM_BUCKETS];
     int64_t mThresholds[NUM_BUCKETS];
+    uint32_t mFrameCounts[128];
 
     int64_t mFrameInterval;
     uint32_t mTotalFrameCount;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index eef4b73..622b570 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -908,15 +908,35 @@
         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
     } else {
         EVENT_LOGD("composeHardwareLayerRect");
+
+        if (USE_GLOPS) {
+            Blend::ModeOrderSwap modeUsage = swap ?
+                    Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap;
+            const Matrix4& transform = swap ? Matrix4::identity() : *currentTransform();
+            bool snap = !swap
+                    && layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
+                    && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
+            Glop glop;
+            GlopBuilder(mRenderState, mCaches, &glop)
+                    .setMeshTexturedUvQuad(nullptr, layer->texCoords)
+                    .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), modeUsage)
+                    .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+                    .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                    .build();
+            renderGlop(glop);
+            return;
+        }
+
         const Rect& texCoords = layer->texCoords;
         resetDrawTextureTexCoords(texCoords.left, texCoords.top,
                 texCoords.right, texCoords.bottom);
 
         float x = rect.left;
         float y = rect.top;
-        bool simpleTransform = currentTransform()->isPureTranslate() &&
-                layer->getWidth() == (uint32_t) rect.getWidth() &&
-                layer->getHeight() == (uint32_t) rect.getHeight();
+        bool simpleTransform = currentTransform()->isPureTranslate()
+                && layer->getWidth() == (uint32_t) rect.getWidth()
+                && layer->getHeight() == (uint32_t) rect.getHeight();
 
         if (simpleTransform) {
             // When we're swapping, the layer is already in screen coordinates
@@ -1053,11 +1073,42 @@
         rects = safeRegion.getArray(&count);
     }
 
-    const float alpha = getLayerAlpha(layer);
     const float texX = 1.0f / float(layer->getWidth());
     const float texY = 1.0f / float(layer->getHeight());
     const float height = rect.getHeight();
 
+    if (USE_GLOPS) {
+        TextureVertex quadVertices[count * 4];
+        //std::unique_ptr<TextureVertex[]> quadVertices(new TextureVertex[count * 4]);
+        TextureVertex* mesh = &quadVertices[0];
+        for (size_t i = 0; i < count; i++) {
+            const android::Rect* r = &rects[i];
+
+            const float u1 = r->left * texX;
+            const float v1 = (height - r->top) * texY;
+            const float u2 = r->right * texX;
+            const float v2 = (height - r->bottom) * texY;
+
+            // TODO: Reject quads outside of the clip
+            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+        }
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
+                .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewOffsetRectSnap(0, 0, rect)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
+        return;
+    }
+
+    const float alpha = getLayerAlpha(layer);
+
     setupDraw();
 
     // We must get (and therefore bind) the region mesh buffer
@@ -2384,7 +2435,7 @@
         ignoreTransform = true;
     }
     drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
-            texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
+            texture->blend, (GLvoid*) mesh->positionOffset, (GLvoid*) mesh->textureOffset,
             GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
             mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
 
@@ -2845,8 +2896,6 @@
     const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-    const bool hasActiveLayer = hasLayer();
-
     TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
     if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
             positions, hasLayer() ? &bounds : nullptr, &functor)) {
@@ -3046,10 +3095,8 @@
     const Rect* clip = &writableSnapshot()->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-    const bool hasActiveLayer = hasLayer();
-
     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
-            hOffset, vOffset, hasActiveLayer ? &bounds : nullptr, &functor)) {
+            hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) {
         dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
         mDirty = true;
     }
@@ -3114,7 +3161,7 @@
                 Glop glop;
                 GlopBuilder(mRenderState, mCaches, &glop)
                         .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
-                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode())
+                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
                         .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
                         .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
                         .setRoundRectClipState(currentSnapshot()->roundRectClipState)
@@ -3600,7 +3647,8 @@
                 mode = SkXfermode::kSrcOver_Mode;
             }
         }
-        mRenderState.blend().enable(mode, swapSrcDst);
+        mRenderState.blend().enable(mode,
+                swapSrcDst ? Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap);
     } else {
         mRenderState.blend().disable();
     }
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index ce51e04..f673c6a 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -24,6 +24,7 @@
 #include "Patch.h"
 #include "Properties.h"
 #include "UvMapper.h"
+#include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -36,19 +37,11 @@
     return verticesCount * sizeof(TextureVertex);
 }
 
-TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
-        float width, float height, const Res_png_9patch* patch) {
-    UvMapper mapper;
-    return createMesh(bitmapWidth, bitmapHeight, width, height, mapper, patch);
-}
-
-TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
-        float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) {
-    if (vertices) return vertices.get();
+Patch::Patch(const float bitmapWidth, const float bitmapHeight,
+        float width, float height, const UvMapper& mapper, const Res_png_9patch* patch)
+        : mColors(patch->getColors()) {
 
     int8_t emptyQuads = 0;
-    mColors = patch->getColors();
-
     const int8_t numColors = patch->numColors;
     if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
         for (int8_t i = 0; i < numColors; i++) {
@@ -64,7 +57,7 @@
     uint32_t yCount = patch->numYDivs;
 
     uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4;
-    if (maxVertices == 0) return nullptr;
+    if (maxVertices == 0) return;
 
     vertices.reset(new TextureVertex[maxVertices]);
     TextureVertex* vertex = vertices.get();
@@ -151,8 +144,6 @@
         memcpy(reducedVertices.get(), vertices.get(), verticesCount * sizeof(TextureVertex));
         vertices = std::move(reducedVertices);
     }
-
-    return vertices.get();
 }
 
 void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
@@ -200,10 +191,10 @@
     const uint32_t oldQuadCount = quadCount;
     quadCount++;
 
-    if (x1 < 0.0f) x1 = 0.0f;
-    if (x2 < 0.0f) x2 = 0.0f;
-    if (y1 < 0.0f) y1 = 0.0f;
-    if (y2 < 0.0f) y2 = 0.0f;
+    x1 = MathUtils::max(x1, 0.0f);
+    x2 = MathUtils::max(x2, 0.0f);
+    y1 = MathUtils::max(y1, 0.0f);
+    y2 = MathUtils::max(y2, 0.0f);
 
     // Skip degenerate and transparent (empty) quads
     if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) {
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 9afb41d..b63bd24 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -39,7 +39,9 @@
 
 class Patch {
 public:
-    Patch() {}
+    Patch(const float bitmapWidth, const float bitmapHeight,
+            float width, float height,
+            const UvMapper& mapper, const Res_png_9patch* patch);
 
     /**
      * Returns the size of this patch's mesh in bytes.
@@ -52,15 +54,9 @@
     bool hasEmptyQuads = false;
     Vector<Rect> quads;
 
-    Rect bounds;
-    GLintptr offset = 0;
+    GLintptr positionOffset = 0;
     GLintptr textureOffset = 0;
 
-    TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight,
-            float width, float height, const Res_png_9patch* patch);
-    TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight,
-            float width, float height, const UvMapper& mapper, const Res_png_9patch* patch);
-
 private:
     void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
             float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
@@ -68,7 +64,7 @@
     void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2, uint32_t& quadCount);
 
-    const uint32_t* mColors = nullptr;
+    const uint32_t* mColors;
     UvMapper mUvMapper;
 }; // struct Patch
 
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index af403b4..2765262 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -162,7 +162,7 @@
 
         // Release the patch and mark the space in the free list
         Patch* patch = pair.getSecond();
-        BufferBlock* block = new BufferBlock(patch->offset, patch->getSize());
+        BufferBlock* block = new BufferBlock(patch->positionOffset, patch->getSize());
         block->next = mFreeBlocks;
         mFreeBlocks = block;
 
@@ -190,7 +190,7 @@
  * Sets the mesh's offsets and copies its associated vertices into
  * the mesh buffer (VBO).
  */
-void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
+void PatchCache::setupMesh(Patch* newMesh) {
     // This call ensures the VBO exists and that it is bound
     init();
 
@@ -223,9 +223,9 @@
     }
 
     // Copy the 9patch mesh in the VBO
-    newMesh->offset = (GLintptr) (block->offset);
-    newMesh->textureOffset = newMesh->offset + kMeshTextureOffset;
-    glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
+    newMesh->positionOffset = (GLintptr) (block->offset);
+    newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset;
+    glBufferSubData(GL_ARRAY_BUFFER, newMesh->positionOffset, size, newMesh->vertices.get());
 
     // Remove the block since we've used it entirely
     if (block->size == size) {
@@ -244,6 +244,8 @@
     mSize += size;
 }
 
+static const UvMapper sIdentity;
+
 const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
         const uint32_t bitmapWidth, const uint32_t bitmapHeight,
         const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
@@ -252,20 +254,12 @@
     const Patch* mesh = mCache.get(description);
 
     if (!mesh) {
-        Patch* newMesh = new Patch();
-        TextureVertex* vertices;
+        const UvMapper& mapper = entry ? entry->uvMapper : sIdentity;
+        Patch* newMesh = new Patch(bitmapWidth, bitmapHeight,
+                pixelWidth, pixelHeight, mapper, patch);
 
-        if (entry) {
-            // An atlas entry has a UV mapper
-            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
-                    pixelWidth, pixelHeight, entry->uvMapper, patch);
-        } else {
-            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
-                    pixelWidth, pixelHeight, patch);
-        }
-
-        if (vertices) {
-            setupMesh(newMesh, vertices);
+        if (newMesh->vertices) {
+            setupMesh(newMesh);
         }
 
 #if DEBUG_PATCHES
@@ -284,7 +278,7 @@
     String8 dump;
     BufferBlock* block = mFreeBlocks;
     while (block) {
-        dump.appendFormat("->(%d, %d)", block->offset, block->size);
+        dump.appendFormat("->(%d, %d)", block->positionOffset, block->size);
         block = block->next;
     }
     ALOGD("%s: Free blocks%s", prefix, dump.string());
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index e038720..387f79a 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -160,7 +160,7 @@
     void clearCache();
     void createVertexBuffer();
 
-    void setupMesh(Patch* newMesh, TextureVertex* vertices);
+    void setupMesh(Patch* newMesh);
 
     void remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch);
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 8c6a91cc..e9b22e2 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -380,9 +380,9 @@
         // Xor
         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
                 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
-        // Add
+        // Plus
         "return min(src + dst, 1.0);\n",
-        // Multiply
+        // Modulate
         "return src * dst;\n",
         // Screen
         "return src + dst - src * dst;\n",
@@ -830,7 +830,7 @@
     while ((index = shader.find("\n", index)) > -1) {
         String8 line(str, index - lastIndex);
         if (line.length() == 0) line.append("\n");
-        PROGRAM_LOGD("%s", line.string());
+        ALOGD("%s", line.string());
         index++;
         str += (index - lastIndex);
         lastIndex = index;
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 1716cf0..c82082f 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -252,6 +252,13 @@
         bottom = fmaxf(bottom, y);
     }
 
+    void expandToCoverRect(float otherLeft, float otherTop, float otherRight, float otherBottom) {
+        left = fminf(left, otherLeft);
+        top = fminf(top, otherTop);
+        right = fmaxf(right, otherRight);
+        bottom = fmaxf(bottom, otherBottom);
+    }
+
     SkRect toSkRect() const {
         return SkRect::MakeLTRB(left, top, right, bottom);
     }
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c6fdd3f..e009451 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -139,7 +139,7 @@
 
 void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) {
     LayerType layerType = properties().layerProperties().type();
-    if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+    if (CC_UNLIKELY(layerType == LayerType::RenderLayer)) {
         // Damage applied so far needs to affect our parent, but does not require
         // the layer to be updated. So we pop/push here to clear out the current
         // damage and get a clean state for display list or children updates to
@@ -156,7 +156,7 @@
     LayerType layerType = properties().layerProperties().type();
     // If we are not a layer OR we cannot be rendered (eg, view was detached)
     // we need to destroy any Layers we may have had previously
-    if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
+    if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable())) {
         if (CC_UNLIKELY(mLayer)) {
             LayerRenderer::destroyLayer(mLayer);
             mLayer = nullptr;
@@ -384,7 +384,7 @@
             renderer.concatMatrix(*properties().getTransformMatrix());
         }
     }
-    const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+    const bool isLayer = properties().layerProperties().type() != LayerType::None;
     int clipFlags = properties().getClippingFlags();
     if (properties().getAlpha() < 1) {
         if (isLayer) {
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index bb6d087..9f1ceed 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -33,14 +33,12 @@
 namespace android {
 namespace uirenderer {
 
-LayerProperties::LayerProperties()
-        : mType(kLayerTypeNone)
-        , mColorFilter(nullptr) {
+LayerProperties::LayerProperties() {
     reset();
 }
 
 LayerProperties::~LayerProperties() {
-    setType(kLayerTypeNone);
+    setType(LayerType::None);
 }
 
 void LayerProperties::reset() {
@@ -146,7 +144,7 @@
         }
     }
 
-    const bool isLayer = layerProperties().type() != kLayerTypeNone;
+    const bool isLayer = layerProperties().type() != LayerType::None;
     int clipFlags = getClippingFlags();
     if (mPrimitiveFields.mAlpha < 1) {
         if (isLayer) {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index f0e22d6..61e98d2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -49,12 +49,12 @@
 #define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
 
 // Keep in sync with View.java:LAYER_TYPE_*
-enum LayerType {
-    kLayerTypeNone = 0,
+enum class LayerType {
+    None = 0,
     // Although we cannot build the software layer directly (must be done at
     // record time), this information is used when applying alpha.
-    kLayerTypeSoftware = 1,
-    kLayerTypeRenderLayer = 2,
+    Software = 1,
+    RenderLayer = 2,
     // TODO: LayerTypeSurfaceTexture? Maybe?
 };
 
@@ -124,12 +124,12 @@
 
     friend class RenderProperties;
 
-    LayerType mType;
+    LayerType mType = LayerType::None;
     // Whether or not that Layer's content is opaque, doesn't include alpha
     bool mOpaque;
     uint8_t mAlpha;
     SkXfermode::Mode mMode;
-    SkColorFilter* mColorFilter;
+    SkColorFilter* mColorFilter = nullptr;
 };
 
 /*
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index efbb709..71088b7 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -22,7 +22,6 @@
 #include <SkDeque.h>
 #include <SkDrawFilter.h>
 #include <SkGraphics.h>
-#include <SkPorterDuff.h>
 #include <SkShader.h>
 #include <SkTArray.h>
 #include <SkTemplates.h>
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 3c65705..ec1bb90 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -22,9 +22,10 @@
 namespace android {
 namespace uirenderer {
 
-SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas)
+SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls)
         : INHERITED(canvas->width(), canvas->height())
-        , mCanvas(canvas) {}
+        , mCanvas(canvas)
+        , mFilterHwuiCalls(filterHwuiCalls) {}
 
 void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
     mCanvas->drawPaint(paint);
@@ -32,6 +33,10 @@
 
 void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
         const SkPaint& paint) {
+    if (!pts || count == 0) {
+        return;
+    }
+
     // convert the SkPoints into floats
     SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
     const size_t floatCount = count << 1;
@@ -118,6 +123,9 @@
 void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
         const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
         int indexCount, const SkPaint& paint) {
+    if (mFilterHwuiCalls) {
+        return;
+    }
     // convert the SkPoints into floats
     SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
     const int floatCount = vertexCount << 1;
@@ -312,6 +320,9 @@
 
 void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
         const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+    if (mFilterHwuiCalls) {
+        return;
+    }
     SkPatchUtils::VertexData data;
 
     SkMatrix matrix;
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index 4322fcf..0de9650 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -27,16 +27,19 @@
 
 /**
  * This class serves as a proxy between Skia's SkCanvas and Android Framework's
- * Canvas.  The class does not maintain any state and will pass through any request
- * directly to the Canvas provided in the constructor.
+ * Canvas.  The class does not maintain any draw-related state and will pass
+ * through most requests directly to the Canvas provided in the constructor.
  *
  * Upon construction it is expected that the provided Canvas has already been
  * prepared for recording and will continue to be in the recording state while
  * this proxy class is being used.
+ *
+ * If filterHwuiCalls is true, the proxy silently ignores away draw calls that
+ * aren't supported by HWUI.
  */
 class ANDROID_API SkiaCanvasProxy : public SkCanvas {
 public:
-    SkiaCanvasProxy(Canvas* canvas);
+    SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls = false);
     virtual ~SkiaCanvasProxy() {}
 
 protected:
@@ -94,6 +97,7 @@
 
 private:
     Canvas* mCanvas;
+    bool mFilterHwuiCalls;
 
     typedef SkCanvas INHERITED;
 };
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index 789f6cc..29927ed 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -78,10 +78,10 @@
     // gl blending off by default
 }
 
-void Blend::enable(SkXfermode::Mode mode, bool swapSrcDst) {
+void Blend::enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage) {
     GLenum srcMode;
     GLenum dstMode;
-    getFactors(mode, swapSrcDst, &srcMode, &dstMode);
+    getFactors(mode, modeUsage, &srcMode, &dstMode);
     setFactors(srcMode, dstMode);
 }
 
@@ -105,9 +105,9 @@
     }
 }
 
-void Blend::getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst) {
-    *outSrc = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src;
-    *outDst = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst;
+void Blend::getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage, GLenum* outSrc, GLenum* outDst) {
+    *outSrc = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].src : kBlends[mode].src;
+    *outDst = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].dst : kBlends[mode].dst;
 }
 
 void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
index 6d0c115c..dcc681d 100644
--- a/libs/hwui/renderstate/Blend.h
+++ b/libs/hwui/renderstate/Blend.h
@@ -29,11 +29,18 @@
 class Blend {
     friend class RenderState;
 public:
-    void enable(SkXfermode::Mode mode, bool swapSrcDst);
+    // dictates whether to swap src/dst
+    enum class ModeOrderSwap {
+        NoSwap,
+        Swap,
+    };
+
+    void enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage);
     void disable();
     void syncEnabled();
 
-    static void getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst);
+    static void getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage,
+            GLenum* outSrc, GLenum* outDst);
     void setFactors(GLenum src, GLenum dst);
 
     void dump();
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 6b00020..0521f65 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -37,7 +37,7 @@
 
     mCurrentBuffer = mUnitQuadBuffer;
 
-    std::unique_ptr<uint16_t[]> regionIndices(new uint16_t[kMaxNumberOfQuads * 6]);
+    uint16_t regionIndices[kMaxNumberOfQuads * 6];
     for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
         uint16_t quad = i * 4;
         int index = i * 6;
@@ -50,8 +50,7 @@
     }
     glGenBuffers(1, &mQuadListIndices);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, kMaxNumberOfQuads * 6 * sizeof(uint16_t),
-            regionIndices.get(), GL_STATIC_DRAW);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(regionIndices), regionIndices, GL_STATIC_DRAW);
     mCurrentIndicesBuffer = mQuadListIndices;
 
     // position attribute always enabled
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index ca3a4c2..7b44d6d 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -259,7 +259,7 @@
     // indices
     meshState().bindIndicesBufferInternal(indices.bufferObject);
 
-    if (vertices.flags & VertexAttribFlags::kTextureCoord) {
+    if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) {
         const Glop::Fill::TextureData& texture = fill.texture;
         // texture always takes slot 0, shader samplers increment from there
         mCaches->textureState().activateTexture(0);
@@ -283,13 +283,13 @@
         meshState().disableTexCoordsVertexArray();
     }
     int colorLocation = -1;
-    if (vertices.flags & VertexAttribFlags::kColor) {
+    if (vertices.attribFlags & VertexAttribFlags::kColor) {
         colorLocation = fill.program->getAttrib("colors");
         glEnableVertexAttribArray(colorLocation);
         glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color);
     }
     int alphaLocation = -1;
-    if (vertices.flags & VertexAttribFlags::kAlpha) {
+    if (vertices.attribFlags & VertexAttribFlags::kAlpha) {
         // NOTE: alpha vertex position is computed assuming no VBO
         const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset;
         alphaLocation = fill.program->getAttrib("vtxAlpha");
@@ -317,7 +317,7 @@
 
             // rebind pointers without forcing, since initial bind handled above
             meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
-            if (vertices.flags & VertexAttribFlags::kTextureCoord) {
+            if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) {
                 meshState().bindTexCoordsVertexPointer(false,
                         vertexData + kMeshTextureOffset, vertices.stride);
             }
@@ -335,10 +335,10 @@
     // -----------------------------------
     // ---------- Mesh teardown ----------
     // -----------------------------------
-    if (vertices.flags & VertexAttribFlags::kAlpha) {
+    if (vertices.attribFlags & VertexAttribFlags::kAlpha) {
         glDisableVertexAttribArray(alphaLocation);
     }
-    if (vertices.flags & VertexAttribFlags::kColor) {
+    if (vertices.attribFlags & VertexAttribFlags::kColor) {
         glDisableVertexAttribArray(colorLocation);
     }
 }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 09f4bac..4526839 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -279,6 +279,7 @@
      * Internal use only
      * @return a combined mask of all flags
      */
+    @SystemApi
     public int getAllFlags() {
         return (mFlags & FLAG_ALL);
     }
@@ -541,14 +542,15 @@
         /**
          * @hide
          * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
-         * REMOTE_SUBMIX and FM_TUNER.
+         * REMOTE_SUBMIX and RADIO_TUNER.
          * @param preset
          * @return the same Builder instance.
          */
+        @SystemApi
         public Builder setInternalCapturePreset(int preset) {
             if ((preset == MediaRecorder.AudioSource.HOTWORD)
                     || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX)
-                    || (preset == MediaRecorder.AudioSource.FM_TUNER)) {
+                    || (preset == MediaRecorder.AudioSource.RADIO_TUNER)) {
                 mSource = preset;
             } else {
                 setCapturePreset(preset);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3a07bef..287b646 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -26,7 +26,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.media.RemoteController.OnClientUpdateListener;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
@@ -59,10 +58,8 @@
 
     private final Context mContext;
     private long mVolumeKeyUpTime;
-    private final boolean mUseMasterVolume;
     private final boolean mUseVolumeKeySounds;
     private final boolean mUseFixedVolume;
-    private final Binder mToken = new Binder();
     private static String TAG = "AudioManager";
     private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
 
@@ -148,17 +145,6 @@
         "android.media.STREAM_MUTE_CHANGED_ACTION";
 
     /**
-     * @hide Broadcast intent when the master volume changes.
-     * Includes the new volume
-     *
-     * @see #EXTRA_MASTER_VOLUME_VALUE
-     * @see #EXTRA_PREV_MASTER_VOLUME_VALUE
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String MASTER_VOLUME_CHANGED_ACTION =
-        "android.media.MASTER_VOLUME_CHANGED_ACTION";
-
-    /**
      * @hide Broadcast intent when the master mute state changes.
      * Includes the the new volume
      *
@@ -210,20 +196,6 @@
         "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
 
     /**
-     * @hide The new master volume value for the master volume changed intent.
-     * Value is integer between 0 and 100 inclusive.
-     */
-    public static final String EXTRA_MASTER_VOLUME_VALUE =
-        "android.media.EXTRA_MASTER_VOLUME_VALUE";
-
-    /**
-     * @hide The previous master volume value for the master volume changed intent.
-     * Value is integer between 0 and 100 inclusive.
-     */
-    public static final String EXTRA_PREV_MASTER_VOLUME_VALUE =
-        "android.media.EXTRA_PREV_MASTER_VOLUME_VALUE";
-
-    /**
      * @hide The new master volume mute state for the master mute changed intent.
      * Value is boolean
      */
@@ -604,8 +576,6 @@
      */
     public AudioManager(Context context) {
         mContext = context;
-        mUseMasterVolume = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
         mUseVolumeKeySounds = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useVolumeKeySounds);
         mUseFixedVolume = mContext.getResources().getBoolean(
@@ -667,12 +637,8 @@
              * The user has hit another key during the delay (e.g., 300ms)
              * since the last volume key up, so cancel any sounds.
              */
-            if (mUseMasterVolume) {
-                adjustMasterVolume(ADJUST_SAME, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
-            } else {
-                adjustSuggestedStreamVolume(ADJUST_SAME,
-                        stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
-            }
+            adjustSuggestedStreamVolume(ADJUST_SAME,
+                    stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
         }
     }
 
@@ -688,22 +654,12 @@
                  * Adjust the volume in on key down since it is more
                  * responsive to the user.
                  */
-                int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
-
-                if (mUseMasterVolume) {
-                    adjustMasterVolume(
-                            keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                    ? ADJUST_RAISE
-                                    : ADJUST_LOWER,
-                            flags);
-                } else {
-                    adjustSuggestedStreamVolume(
-                            keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                    ? ADJUST_RAISE
-                                    : ADJUST_LOWER,
-                            stream,
-                            flags);
-                }
+                adjustSuggestedStreamVolume(
+                        keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                                ? ADJUST_RAISE
+                                : ADJUST_LOWER,
+                        stream,
+                        FLAG_SHOW_UI | FLAG_VIBRATE);
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
                 if (event.getRepeatCount() == 0) {
@@ -726,15 +682,10 @@
                  * sound to play when a user holds down volume down to mute.
                  */
                 if (mUseVolumeKeySounds) {
-                    if (mUseMasterVolume) {
-                        adjustMasterVolume(ADJUST_SAME, FLAG_PLAY_SOUND);
-                    } else {
-                        int flags = FLAG_PLAY_SOUND;
-                        adjustSuggestedStreamVolume(
-                                ADJUST_SAME,
-                                stream,
-                                flags);
-                    }
+                    adjustSuggestedStreamVolume(
+                            ADJUST_SAME,
+                            stream,
+                            FLAG_PLAY_SOUND);
                 }
                 mVolumeKeyUpTime = SystemClock.uptimeMillis();
                 break;
@@ -783,12 +734,8 @@
     public void adjustStreamVolume(int streamType, int direction, int flags) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
-            } else {
-                service.adjustStreamVolume(streamType, direction, flags,
-                        mContext.getOpPackageName());
-            }
+            service.adjustStreamVolume(streamType, direction, flags,
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustStreamVolume", e);
         }
@@ -818,17 +765,8 @@
      * @see #isVolumeFixed()
      */
     public void adjustVolume(int direction, int flags) {
-        IAudioService service = getService();
-        try {
-            if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
-            } else {
-                MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-                helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustVolume", e);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+        helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
     }
 
     /**
@@ -856,34 +794,17 @@
      * @see #isVolumeFixed()
      */
     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
-        IAudioService service = getService();
-        try {
-            if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
-            } else {
-                MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-                helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+        helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
     }
 
-    /**
-     * Adjusts the master volume for the device's audio amplifier.
-     * <p>
-     *
-     * @param steps The number of volume steps to adjust. A positive
-     *            value will raise the volume.
-     * @param flags One or more flags.
-     * @hide
-     */
-    public void adjustMasterVolume(int steps, int flags) {
+    /** @hide */
+    public void setMasterMute(boolean mute, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustMasterVolume(steps, flags, mContext.getOpPackageName());
+            service.setMasterMute(mute, flags, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustMasterVolume", e);
+            Log.e(TAG, "Dead object in setMasterMute", e);
         }
     }
 
@@ -935,11 +856,7 @@
     public int getStreamMaxVolume(int streamType) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                return service.getMasterMaxVolume();
-            } else {
-                return service.getStreamMaxVolume(streamType);
-            }
+            return service.getStreamMaxVolume(streamType);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getStreamMaxVolume", e);
             return 0;
@@ -957,11 +874,7 @@
     public int getStreamVolume(int streamType) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                return service.getMasterVolume();
-            } else {
-                return service.getStreamVolume(streamType);
-            }
+            return service.getStreamVolume(streamType);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getStreamVolume", e);
             return 0;
@@ -976,11 +889,7 @@
     public int getLastAudibleStreamVolume(int streamType) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                return service.getLastAudibleMasterVolume();
-            } else {
-                return service.getLastAudibleStreamVolume(streamType);
-            }
+            return service.getLastAudibleStreamVolume(streamType);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
             return 0;
@@ -993,12 +902,12 @@
      * It is assumed that this stream type is also tied to ringer mode changes.
      * @hide
      */
-    public int getMasterStreamType() {
+    public int getUiSoundsStreamType() {
         IAudioService service = getService();
         try {
-            return service.getMasterStreamType();
+            return service.getUiSoundsStreamType();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getMasterStreamType", e);
+            Log.e(TAG, "Dead object in getUiSoundsStreamType", e);
             return STREAM_RING;
         }
     }
@@ -1043,82 +952,13 @@
     public void setStreamVolume(int streamType, int index, int flags) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                service.setMasterVolume(index, flags, mContext.getOpPackageName());
-            } else {
-                service.setStreamVolume(streamType, index, flags, mContext.getOpPackageName());
-            }
+            service.setStreamVolume(streamType, index, flags, mContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setStreamVolume", e);
         }
     }
 
     /**
-     * Returns the maximum volume index for master volume.
-     *
-     * @hide
-     */
-    public int getMasterMaxVolume() {
-        IAudioService service = getService();
-        try {
-            return service.getMasterMaxVolume();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getMasterMaxVolume", e);
-            return 0;
-        }
-    }
-
-    /**
-     * Returns the current volume index for master volume.
-     *
-     * @return The current volume index for master volume.
-     * @hide
-     */
-    public int getMasterVolume() {
-        IAudioService service = getService();
-        try {
-            return service.getMasterVolume();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getMasterVolume", e);
-            return 0;
-        }
-    }
-
-    /**
-     * Get last audible volume before master volume was muted.
-     *
-     * @hide
-     */
-    public int getLastAudibleMasterVolume() {
-        IAudioService service = getService();
-        try {
-            return service.getLastAudibleMasterVolume();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getLastAudibleMasterVolume", e);
-            return 0;
-        }
-    }
-
-    /**
-     * Sets the volume index for master volume.
-     *
-     * @param index The volume index to set. See
-     *            {@link #getMasterMaxVolume()} for the largest valid value.
-     * @param flags One or more flags.
-     * @see #getMasterMaxVolume()
-     * @see #getMasterVolume()
-     * @hide
-     */
-    public void setMasterVolume(int index, int flags) {
-        IAudioService service = getService();
-        try {
-            service.setMasterVolume(index, flags, mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMasterVolume", e);
-        }
-    }
-
-    /**
      * Solo or unsolo a particular stream.
      * <p>
      * Do not use. This method has been deprecated and is now a no-op.
@@ -1189,11 +1029,7 @@
     public boolean isStreamMute(int streamType) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                return service.isMasterMute();
-            } else {
-                return service.isStreamMute(streamType);
-            }
+            return service.isStreamMute(streamType);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in isStreamMute", e);
             return false;
@@ -1223,9 +1059,6 @@
      * @hide
      */
     public void forceVolumeControlStream(int streamType) {
-        if (mUseMasterVolume) {
-            return;
-        }
         IAudioService service = getService();
         try {
             service.forceVolumeControlStream(streamType, mICallBack);
@@ -2694,7 +2527,7 @@
      * metadata updates and playback state information from applications using
      * {@link RemoteControlClient}, and control their playback.
      * <p>
-     * Registration requires the {@link OnClientUpdateListener} listener to be
+     * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
      * one of the enabled notification listeners (see
      * {@link android.service.notification.NotificationListenerService}).
      *
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index ef5710c..059d940 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -36,9 +36,6 @@
     public abstract void setStreamVolumeForUid(int streamType, int direction, int flags,
             String callingPackage, int uid);
 
-    public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
-            int uid);
-
     public abstract void setRingerModeDelegate(RingerModeDelegate delegate);
 
     public abstract int getRingerModeInternal();
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index de10ef9..259fe37 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -20,6 +20,7 @@
 import java.nio.ByteBuffer;
 import java.util.Iterator;
 
+import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -238,7 +239,6 @@
 
     /**
      * @hide
-     * CANDIDATE FOR PUBLIC API
      * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
      * @param attributes a non-null {@link AudioAttributes} instance. Use
      *     {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the capture
@@ -257,6 +257,7 @@
      *   construction.
      * @throws IllegalArgumentException
      */
+    @SystemApi
     public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
             int sessionId) throws IllegalArgumentException {
         mRecordingState = RECORDSTATE_STOPPED;
@@ -376,7 +377,7 @@
         // audio source
         if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
              ((audioSource > MediaRecorder.getAudioSourceMax()) &&
-              (audioSource != MediaRecorder.AudioSource.FM_TUNER) &&
+              (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) &&
               (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
             throw new IllegalArgumentException("Invalid audio source.");
         }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 17f5b59..20f7d29 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -44,32 +44,24 @@
 
     void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
 
-    void adjustMasterVolume(int direction, int flags, String callingPackage);
-
     void setStreamVolume(int streamType, int index, int flags, String callingPackage);
 
     oneway void setRemoteStreamVolume(int index);
 
-    void setMasterVolume(int index, int flags, String callingPackage);
-
     boolean isStreamMute(int streamType);
 
     void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb);
 
     boolean isMasterMute();
 
-    int getStreamVolume(int streamType);
+    void setMasterMute(boolean mute, int flags, String callingPackage);
 
-    int getMasterVolume();
+    int getStreamVolume(int streamType);
 
     int getStreamMaxVolume(int streamType);
 
-    int getMasterMaxVolume();
-
     int getLastAudibleStreamVolume(int streamType);
 
-    int getLastAudibleMasterVolume();
-
     void setMicrophoneMute(boolean on, String callingPackage);
 
     void setRingerModeExternal(int ringerMode, String caller);
@@ -187,7 +179,7 @@
 
     void setRingtonePlayer(IRingtonePlayer player);
     IRingtonePlayer getRingtonePlayer();
-    int getMasterStreamType();
+    int getUiSoundsStreamType();
 
     void setWiredDeviceConnectionState(int type, int state, String address, String name);
     int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
diff --git a/media/java/android/media/IVolumeController.aidl b/media/java/android/media/IVolumeController.aidl
index e3593a6..90ac416 100644
--- a/media/java/android/media/IVolumeController.aidl
+++ b/media/java/android/media/IVolumeController.aidl
@@ -27,8 +27,6 @@
 
     void volumeChanged(int streamType, int flags);
 
-    void masterVolumeChanged(int flags);
-
     void masterMuteChanged(int flags);
 
     void setLayoutDirection(int layoutDirection);
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 8d6a588..824a7ad 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -483,6 +483,8 @@
             case ImageFormat.Y16:
             case ImageFormat.RAW_SENSOR:
             case ImageFormat.RAW10:
+            case ImageFormat.DEPTH16:
+            case ImageFormat.DEPTH_POINT_CLOUD:
                 return 1;
             default:
                 throw new UnsupportedOperationException(
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 97b3f63..58c86f2 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.hardware.Camera;
 import android.os.Handler;
@@ -222,12 +223,11 @@
         public static final int REMOTE_SUBMIX = 8;
 
         /**
-         * Audio source for FM, which is used to capture current FM tuner output by FMRadio app.
-         * There are two use cases, one is for record FM stream for later listening, another is
-         * for FM indirect mode(the routing except FM to headset(headphone) device routing).
+         * Audio source for capturing broadcast radio tuner output.
          * @hide
          */
-        public static final int FM_TUNER = 1998;
+        @SystemApi
+        public static final int RADIO_TUNER = 1998;
 
         /**
          * Audio source for preemptible, low-priority software hotword detection
@@ -240,7 +240,8 @@
          * This is a hidden audio source.
          * @hide
          */
-        protected static final int HOTWORD = 1999;
+        @SystemApi
+        public static final int HOTWORD = 1999;
     }
 
     /**
diff --git a/media/java/android/media/midi/IMidiListener.aidl b/media/java/android/media/midi/IMidiDeviceListener.aidl
similarity index 95%
rename from media/java/android/media/midi/IMidiListener.aidl
rename to media/java/android/media/midi/IMidiDeviceListener.aidl
index a4129e9..17d9bfd 100644
--- a/media/java/android/media/midi/IMidiListener.aidl
+++ b/media/java/android/media/midi/IMidiDeviceListener.aidl
@@ -19,7 +19,7 @@
 import android.media.midi.MidiDeviceInfo;
 
 /** @hide */
-oneway interface IMidiListener
+oneway interface IMidiDeviceListener
 {
     void onDeviceAdded(in MidiDeviceInfo device);
     void onDeviceRemoved(in MidiDeviceInfo device);
diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
index 71914ad..3331aae 100644
--- a/media/java/android/media/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -21,6 +21,7 @@
 /** @hide */
 interface IMidiDeviceServer
 {
-    ParcelFileDescriptor openInputPort(int portNumber);
-    ParcelFileDescriptor openOutputPort(int portNumber);
+    ParcelFileDescriptor openInputPort(IBinder token, int portNumber);
+    ParcelFileDescriptor openOutputPort(IBinder token, int portNumber);
+    void closePort(IBinder token);
 }
diff --git a/media/java/android/media/midi/IMidiManager.aidl b/media/java/android/media/midi/IMidiManager.aidl
index bba35f5..617b03e 100644
--- a/media/java/android/media/midi/IMidiManager.aidl
+++ b/media/java/android/media/midi/IMidiManager.aidl
@@ -16,8 +16,8 @@
 
 package android.media.midi;
 
+import android.media.midi.IMidiDeviceListener;
 import android.media.midi.IMidiDeviceServer;
-import android.media.midi.IMidiListener;
 import android.media.midi.MidiDeviceInfo;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -28,14 +28,20 @@
     MidiDeviceInfo[] getDeviceList();
 
     // for device creation & removal notifications
-    void registerListener(IBinder token, in IMidiListener listener);
-    void unregisterListener(IBinder token, in IMidiListener listener);
+    void registerListener(IBinder token, in IMidiDeviceListener listener);
+    void unregisterListener(IBinder token, in IMidiDeviceListener listener);
 
-    // for communicating with MIDI devices
+    // for opening built-in MIDI devices
     IMidiDeviceServer openDevice(IBinder token, in MidiDeviceInfo device);
 
-    // for implementing virtual MIDI devices
+    // for registering built-in MIDI devices
     MidiDeviceInfo registerDeviceServer(in IMidiDeviceServer server, int numInputPorts,
-            int numOutputPorts, in Bundle properties, boolean isPrivate, int type);
+            int numOutputPorts, in Bundle properties, int type);
+
+    // for unregistering built-in MIDI devices
     void unregisterDeviceServer(in IMidiDeviceServer server);
+
+    // used by MidiDeviceService to access the MidiDeviceInfo that was created based on its
+    // manifest's meta-data
+    MidiDeviceInfo getServiceDeviceInfo(String packageName, String className);
 }
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index 87af362..af0737d 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -16,30 +16,47 @@
 
 package android.media.midi;
 
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Log;
 
+import dalvik.system.CloseGuard;
+
+import java.io.Closeable;
+import java.io.IOException;
+
 /**
- * This class is used for sending and receiving data to and from an MIDI device
+ * This class is used for sending and receiving data to and from a MIDI device
  * Instances of this class are created by {@link MidiManager#openDevice}.
  *
  * CANDIDATE FOR PUBLIC API
  * @hide
  */
-public final class MidiDevice {
+public final class MidiDevice implements Closeable {
     private static final String TAG = "MidiDevice";
 
     private final MidiDeviceInfo mDeviceInfo;
-    private final IMidiDeviceServer mServer;
+    private final IMidiDeviceServer mDeviceServer;
+    private Context mContext;
+    private ServiceConnection mServiceConnection;
 
-   /**
-     * MidiDevice should only be instantiated by MidiManager
-     * @hide
-     */
-    public MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
+    private final CloseGuard mGuard = CloseGuard.get();
+
+    /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
+        this(deviceInfo, server, null, null);
+    }
+
+    /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server,
+            Context context, ServiceConnection serviceConnection) {
         mDeviceInfo = deviceInfo;
-        mServer = server;
+        mDeviceServer = server;
+        mContext = context;
+        mServiceConnection = serviceConnection;
+        mGuard.open("close");
     }
 
     /**
@@ -59,11 +76,12 @@
      */
     public MidiInputPort openInputPort(int portNumber) {
         try {
-            ParcelFileDescriptor pfd = mServer.openInputPort(portNumber);
+            IBinder token = new Binder();
+            ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
             if (pfd == null) {
                 return null;
             }
-            return new MidiInputPort(pfd, portNumber);
+            return new MidiInputPort(mDeviceServer, token, pfd, portNumber);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in openInputPort");
             return null;
@@ -78,11 +96,12 @@
      */
     public MidiOutputPort openOutputPort(int portNumber) {
         try {
-            ParcelFileDescriptor pfd = mServer.openOutputPort(portNumber);
+            IBinder token = new Binder();
+            ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
             if (pfd == null) {
                 return null;
             }
-            return new MidiOutputPort(pfd, portNumber);
+            return new MidiOutputPort(mDeviceServer, token, pfd, portNumber);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in openOutputPort");
             return null;
@@ -90,6 +109,28 @@
     }
 
     @Override
+    public void close() throws IOException {
+        synchronized (mGuard) {
+            mGuard.close();
+            if (mContext != null && mServiceConnection != null) {
+                mContext.unbindService(mServiceConnection);
+                mContext = null;
+                mServiceConnection = null;
+            }
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
     public String toString() {
         return ("MidiDevice: " + mDeviceInfo.toString());
     }
diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
index fd35052..1e97258 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.java
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -31,7 +31,7 @@
  * CANDIDATE FOR PUBLIC API
  * @hide
  */
-public class MidiDeviceInfo implements Parcelable {
+public final class MidiDeviceInfo implements Parcelable {
 
     private static final String TAG = "MidiDeviceInfo";
 
@@ -50,6 +50,7 @@
     private final int mInputPortCount;
     private final int mOutputPortCount;
     private final Bundle mProperties;
+    private final boolean mIsPrivate;
 
     /**
      * Bundle key for the device's manufacturer name property.
@@ -83,6 +84,8 @@
      * Bundle key for the device's ALSA card number.
      * Only set for USB MIDI devices.
      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     *
+     * @hide
      */
     public static final String PROPERTY_ALSA_CARD = "alsa_card";
 
@@ -90,20 +93,32 @@
      * Bundle key for the device's ALSA device number.
      * Only set for USB MIDI devices.
      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     *
+     * @hide
      */
     public static final String PROPERTY_ALSA_DEVICE = "alsa_device";
 
     /**
+     * {@link android.content.pm.ServiceInfo} for the service hosting the device implementation.
+     * Only set for Virtual MIDI devices.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     *
+     * @hide
+     */
+    public static final String PROPERTY_SERVICE_INFO = "service_info";
+
+    /**
      * MidiDeviceInfo should only be instantiated by MidiService implementation
      * @hide
      */
     public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
-            Bundle properties) {
+            Bundle properties, boolean isPrivate) {
         mType = type;
         mId = id;
         mInputPortCount = numInputPorts;
         mOutputPortCount = numOutputPorts;
         mProperties = properties;
+        mIsPrivate = isPrivate;
     }
 
     /**
@@ -152,6 +167,16 @@
         return mProperties;
     }
 
+    /**
+     * Returns true if the device is private.  Private devices are only visible and accessible
+     * to clients with the same UID as the application that is hosting the device.
+     *
+     * @return true if the device is private
+     */
+    public boolean isPrivate() {
+        return mIsPrivate;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o instanceof MidiDeviceInfo) {
@@ -171,7 +196,8 @@
         return ("MidiDeviceInfo[mType=" + mType +
                 ",mInputPortCount=" + mInputPortCount +
                 ",mOutputPortCount=" + mOutputPortCount +
-                ",mProperties=" + mProperties);
+                ",mProperties=" + mProperties +
+                ",mIsPrivate=" + mIsPrivate);
     }
 
     public static final Parcelable.Creator<MidiDeviceInfo> CREATOR =
@@ -182,7 +208,8 @@
             int inputPorts = in.readInt();
             int outputPorts = in.readInt();
             Bundle properties = in.readBundle();
-            return new MidiDeviceInfo(type, id, inputPorts, outputPorts, properties);
+            boolean isPrivate = (in.readInt() == 1);
+            return new MidiDeviceInfo(type, id, inputPorts, outputPorts, properties, isPrivate);
         }
 
         public MidiDeviceInfo[] newArray(int size) {
@@ -200,5 +227,6 @@
         parcel.writeInt(mInputPortCount);
         parcel.writeInt(mOutputPortCount);
         parcel.writeBundle(mProperties);
+        parcel.writeInt(mIsPrivate ? 1 : 0);
    }
 }
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index 3317baa..3b4b6f0 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -16,21 +16,26 @@
 
 package android.media.midi;
 
+import android.os.IBinder;
+import android.os.Binder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.system.OsConstants;
 import android.util.Log;
 
+import dalvik.system.CloseGuard;
+
+import libcore.io.IoUtils;
+
 import java.io.Closeable;
 import java.io.IOException;
-import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
- * This class is used to provide the implemention of MIDI device.
- * Applications may call {@link MidiManager#createDeviceServer}
- * to create an instance of this class to implement a virtual MIDI device.
+ * Internal class used for providing an implementation for a MIDI device.
  *
- * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public final class MidiDeviceServer implements Closeable {
@@ -40,64 +45,100 @@
 
     // MidiDeviceInfo for the device implemented by this server
     private MidiDeviceInfo mDeviceInfo;
-    private int mInputPortCount;
-    private int mOutputPortCount;
+    private final int mInputPortCount;
+    private final int mOutputPortCount;
 
-    // output ports for receiving messages from our clients
-    // we can have only one per port number
-    private MidiOutputPort[] mInputPortSenders;
+    // MidiReceivers for receiving data on our input ports
+    private final MidiReceiver[] mInputPortReceivers;
 
-    // receivers attached to our input ports
-    private ArrayList<MidiReceiver>[] mInputPortReceivers;
+    // MidiDispatchers for sending data on our output ports
+    private MidiDispatcher[] mOutputPortDispatchers;
 
-    // input ports for sending messages to our clients
-    // we can have multiple outputs per port number
-    private ArrayList<MidiInputPort>[] mOutputPortReceivers;
+    // MidiOutputPorts for clients connected to our input ports
+    private final MidiOutputPort[] mInputPortOutputPorts;
 
-    // subclass of MidiInputPort for passing to clients
-    // that notifies us when the connection has failed
-    private class ServerInputPort extends MidiInputPort {
-        ServerInputPort(ParcelFileDescriptor pfd, int portNumber) {
-            super(pfd, portNumber);
+    // List of all MidiInputPorts we created
+    private final CopyOnWriteArrayList<MidiInputPort> mInputPorts
+            = new CopyOnWriteArrayList<MidiInputPort>();
+
+    private final CloseGuard mGuard = CloseGuard.get();
+
+    abstract private class PortClient implements IBinder.DeathRecipient {
+        final IBinder mToken;
+
+        PortClient(IBinder token) {
+            mToken = token;
+
+            try {
+                token.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                close();
+            }
         }
 
+        abstract void close();
+
         @Override
-        public void onIOException() {
-            synchronized (mOutputPortReceivers) {
-                mOutputPortReceivers[getPortNumber()].clear();
-            }
+        public void binderDied() {
+            close();
         }
     }
 
-    // subclass of MidiOutputPort for passing to clients
-    // that notifies us when the connection has failed
-    private class ServerOutputPort extends MidiOutputPort {
-        ServerOutputPort(ParcelFileDescriptor pfd, int portNumber) {
-            super(pfd, portNumber);
+    private class InputPortClient extends PortClient {
+        private final MidiOutputPort mOutputPort;
+
+        InputPortClient(IBinder token, MidiOutputPort outputPort) {
+            super(token);
+            mOutputPort = outputPort;
         }
 
         @Override
-        public void onIOException() {
-            synchronized (mInputPortSenders) {
-                mInputPortSenders[getPortNumber()] = null;
+        void close() {
+            mToken.unlinkToDeath(this, 0);
+            synchronized (mInputPortOutputPorts) {
+                mInputPortOutputPorts[mOutputPort.getPortNumber()] = null;
             }
+            IoUtils.closeQuietly(mOutputPort);
         }
     }
 
+    private class OutputPortClient extends PortClient {
+        private final MidiInputPort mInputPort;
+
+        OutputPortClient(IBinder token, MidiInputPort inputPort) {
+            super(token);
+            mInputPort = inputPort;
+        }
+
+        @Override
+        void close() {
+            mToken.unlinkToDeath(this, 0);
+            mOutputPortDispatchers[mInputPort.getPortNumber()].getSender().disconnect(mInputPort);
+            mInputPorts.remove(mInputPort);
+            IoUtils.closeQuietly(mInputPort);
+        }
+    }
+
+    private final HashMap<IBinder, PortClient> mPortClients = new HashMap<IBinder, PortClient>();
+
     // Binder interface stub for receiving connection requests from clients
     private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() {
 
         @Override
-        public ParcelFileDescriptor openInputPort(int portNumber) {
+        public ParcelFileDescriptor openInputPort(IBinder token, int portNumber) {
+            if (mDeviceInfo.isPrivate()) {
+                if (Binder.getCallingUid() != Process.myUid()) {
+                    throw new SecurityException("Can't access private device from different UID");
+                }
+            }
+
             if (portNumber < 0 || portNumber >= mInputPortCount) {
                 Log.e(TAG, "portNumber out of range in openInputPort: " + portNumber);
                 return null;
             }
 
-            ParcelFileDescriptor result = null;
-
-            synchronized (mInputPortSenders) {
-                if (mInputPortSenders[portNumber] != null) {
+            synchronized (mInputPortOutputPorts) {
+                if (mInputPortOutputPorts[portNumber] != null) {
                     Log.d(TAG, "port " + portNumber + " already open");
                     return null;
                 }
@@ -105,47 +146,77 @@
                 try {
                     ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
                                                         OsConstants.SOCK_SEQPACKET);
-                    MidiOutputPort newOutputPort = new ServerOutputPort(pair[0], portNumber);
-                    mInputPortSenders[portNumber] = newOutputPort;
-                    result =  pair[1];
-
-                    ArrayList<MidiReceiver> receivers = mInputPortReceivers[portNumber];
-                    synchronized (receivers) {
-                        for (int i = 0; i < receivers.size(); i++) {
-                            newOutputPort.connect(receivers.get(i));
-                        }
+                    MidiOutputPort outputPort = new MidiOutputPort(pair[0], portNumber);
+                    mInputPortOutputPorts[portNumber] = outputPort;
+                    outputPort.connect(mInputPortReceivers[portNumber]);
+                    InputPortClient client = new InputPortClient(token, outputPort);
+                    synchronized (mPortClients) {
+                        mPortClients.put(token, client);
                     }
+                    return pair[1];
                 } catch (IOException e) {
                     Log.e(TAG, "unable to create ParcelFileDescriptors in openInputPort");
                     return null;
                 }
             }
-
-            return result;
         }
 
         @Override
-        public ParcelFileDescriptor openOutputPort(int portNumber) {
+        public ParcelFileDescriptor openOutputPort(IBinder token, int portNumber) {
+            if (mDeviceInfo.isPrivate()) {
+                if (Binder.getCallingUid() != Process.myUid()) {
+                    throw new SecurityException("Can't access private device from different UID");
+                }
+            }
+
             if (portNumber < 0 || portNumber >= mOutputPortCount) {
                 Log.e(TAG, "portNumber out of range in openOutputPort: " + portNumber);
                 return null;
             }
-            synchronized (mOutputPortReceivers) {
-                try {
-                    ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
-                                                        OsConstants.SOCK_SEQPACKET);
-                    mOutputPortReceivers[portNumber].add(new ServerInputPort(pair[0], portNumber));
-                    return pair[1];
-                } catch (IOException e) {
-                    Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
-                    return null;
+
+            try {
+                ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
+                                                    OsConstants.SOCK_SEQPACKET);
+                MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber);
+                mOutputPortDispatchers[portNumber].getSender().connect(inputPort);
+                mInputPorts.add(inputPort);
+                OutputPortClient client = new OutputPortClient(token, inputPort);
+                synchronized (mPortClients) {
+                    mPortClients.put(token, client);
+                }
+                return pair[1];
+            } catch (IOException e) {
+                Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
+                return null;
+            }
+        }
+
+        @Override
+        public void closePort(IBinder token) {
+            synchronized (mPortClients) {
+                PortClient client = mPortClients.remove(token);
+                if (client != null) {
+                    client.close();
                 }
             }
         }
     };
 
-    /* package */ MidiDeviceServer(IMidiManager midiManager) {
+    /* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,
+            int numOutputPorts) {
         mMidiManager = midiManager;
+        mInputPortReceivers = inputPortReceivers;
+        mInputPortCount = inputPortReceivers.length;
+        mOutputPortCount = numOutputPorts;
+
+        mInputPortOutputPorts = new MidiOutputPort[mInputPortCount];
+
+        mOutputPortDispatchers = new MidiDispatcher[numOutputPorts];
+        for (int i = 0; i < numOutputPorts; i++) {
+            mOutputPortDispatchers[i] = new MidiDispatcher();
+        }
+
+        mGuard.open("close");
     }
 
     /* package */ IMidiDeviceServer getBinderInterface() {
@@ -157,112 +228,50 @@
             throw new IllegalStateException("setDeviceInfo should only be called once");
         }
         mDeviceInfo = deviceInfo;
-        mInputPortCount = deviceInfo.getInputPortCount();
-        mOutputPortCount = deviceInfo.getOutputPortCount();
-        mInputPortSenders = new MidiOutputPort[mInputPortCount];
-
-        mInputPortReceivers = new ArrayList[mInputPortCount];
-        for (int i = 0; i < mInputPortCount; i++) {
-            mInputPortReceivers[i] = new ArrayList<MidiReceiver>();
-        }
-
-        mOutputPortReceivers = new ArrayList[mOutputPortCount];
-        for (int i = 0; i < mOutputPortCount; i++) {
-            mOutputPortReceivers[i] = new ArrayList<MidiInputPort>();
-        }
     }
 
     @Override
     public void close() throws IOException {
+        synchronized (mGuard) {
+            mGuard.close();
+
+            for (int i = 0; i < mInputPortCount; i++) {
+                MidiOutputPort outputPort = mInputPortOutputPorts[i];
+                if (outputPort != null) {
+                    IoUtils.closeQuietly(outputPort);
+                    mInputPortOutputPorts[i] = null;
+                }
+            }
+            for (MidiInputPort inputPort : mInputPorts) {
+                IoUtils.closeQuietly(inputPort);
+            }
+            mInputPorts.clear();
+            try {
+                mMidiManager.unregisterDeviceServer(mServer);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in unregisterDeviceServer");
+            }
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
         try {
-            // FIXME - close input and output ports too?
-            mMidiManager.unregisterDeviceServer(mServer);
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in unregisterDeviceServer");
+            mGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
         }
     }
 
     /**
-     * Returns a {@link MidiDeviceInfo} object, which describes this device.
-     *
-     * @return the {@link MidiDeviceInfo} object
+     * Returns an array of {@link MidiReceiver} for the device's output ports.
+     * Clients can use these receivers to send data out the device's output ports.
+     * @return array of MidiReceivers
      */
-    public MidiDeviceInfo getInfo() {
-        return mDeviceInfo;
-    }
-
-    /**
-     * Called to open a {@link MidiSender} to allow receiving MIDI messages
-     * on the device's input port for the specified port number.
-     *
-     * @param portNumber the number of the input port
-     * @return the {@link MidiSender}
-     */
-    public MidiSender openInputPortSender(int portNumber) {
-        if (portNumber < 0 || portNumber >= mDeviceInfo.getInputPortCount()) {
-            throw new IllegalArgumentException("portNumber " + portNumber + " out of range");
-        }
-        final int portNumberF = portNumber;
-        return new MidiSender() {
-
-            @Override
-            public void connect(MidiReceiver receiver) {
-                // We always synchronize on mInputPortSenders before receivers if we need to
-                // synchronize on both.
-                synchronized (mInputPortSenders) {
-                    ArrayList<MidiReceiver> receivers = mInputPortReceivers[portNumberF];
-                    synchronized (receivers) {
-                        receivers.add(receiver);
-                        MidiOutputPort outputPort = mInputPortSenders[portNumberF];
-                        if (outputPort != null) {
-                            outputPort.connect(receiver);
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public void disconnect(MidiReceiver receiver) {
-                // We always synchronize on mInputPortSenders before receivers if we need to
-                // synchronize on both.
-                synchronized (mInputPortSenders) {
-                    ArrayList<MidiReceiver> receivers = mInputPortReceivers[portNumberF];
-                    synchronized (receivers) {
-                        receivers.remove(receiver);
-                        MidiOutputPort outputPort = mInputPortSenders[portNumberF];
-                        if (outputPort != null) {
-                            outputPort.disconnect(receiver);
-                        }
-                    }
-                }
-            }
-        };
-    }
-
-    /**
-     * Called to open a {@link MidiReceiver} to allow sending MIDI messages
-     * on the virtual device's output port for the specified port number.
-     *
-     * @param portNumber the number of the output port
-     * @return the {@link MidiReceiver}
-     */
-    public MidiReceiver openOutputPortReceiver(int portNumber) {
-        if (portNumber < 0 || portNumber >= mDeviceInfo.getOutputPortCount()) {
-            throw new IllegalArgumentException("portNumber " + portNumber + " out of range");
-        }
-        final int portNumberF = portNumber;
-        return new MidiReceiver() {
-
-            @Override
-            public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
-                ArrayList<MidiInputPort> receivers = mOutputPortReceivers[portNumberF];
-                synchronized (receivers) {
-                    for (int i = 0; i < receivers.size(); i++) {
-                        // FIXME catch errors and remove dead ones
-                        receivers.get(i).post(msg, offset, count, timestamp);
-                    }
-                }
-            }
-        };
+    public MidiReceiver[] getOutputPortReceivers() {
+        MidiReceiver[] receivers = new MidiReceiver[mOutputPortCount];
+        System.arraycopy(mOutputPortDispatchers, 0, receivers, 0, mOutputPortCount);
+        return receivers;
     }
 }
diff --git a/media/java/android/media/midi/MidiDeviceService.java b/media/java/android/media/midi/MidiDeviceService.java
new file mode 100644
index 0000000..64f69cd
--- /dev/null
+++ b/media/java/android/media/midi/MidiDeviceService.java
@@ -0,0 +1,125 @@
+/*
+ * 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.media.midi;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * A service that implements a virtual MIDI device.
+ * Subclasses must implement the {@link #getInputPortReceivers} method to provide a
+ * list of {@link MidiReceiver}s to receive data sent to the device's input ports.
+ * Similarly, subclasses can call {@link #getOutputPortReceivers} to fetch a list
+ * of {@link MidiReceiver}s for sending data out the output ports.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * an intent filter with the {@link #SERVICE_INTERFACE} action
+ * and meta-data to describe the virtual device.
+ For example:</p>
+ * <pre>
+ * &lt;service android:name=".VirtualDeviceService"
+ *          android:label="&#64;string/service_name">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.media.midi.MidiDeviceService" />
+ *     &lt;/intent-filter>
+ *           &lt;meta-data android:name="android.media.midi.MidiDeviceService"
+                android:resource="@xml/device_info" />
+ * &lt;/service></pre>
+ *
+ * CANDIDATE FOR PUBLIC API
+ * @hide
+ */
+abstract public class MidiDeviceService extends Service {
+    private static final String TAG = "MidiDeviceService";
+
+    public static final String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
+
+    private IMidiManager mMidiManager;
+    private MidiDeviceServer mServer;
+    private MidiDeviceInfo mDeviceInfo;
+
+    @Override
+    public void onCreate() {
+        mMidiManager = IMidiManager.Stub.asInterface(
+                    ServiceManager.getService(Context.MIDI_SERVICE));
+        MidiDeviceServer server;
+        try {
+            MidiDeviceInfo deviceInfo = mMidiManager.getServiceDeviceInfo(getPackageName(),
+                    this.getClass().getName());
+            if (deviceInfo == null) {
+                Log.e(TAG, "Could not find MidiDeviceInfo for MidiDeviceService " + this);
+                return;
+            }
+            mDeviceInfo = deviceInfo;
+            MidiReceiver[] inputPortReceivers = getInputPortReceivers();
+            if (inputPortReceivers == null) {
+                inputPortReceivers = new MidiReceiver[0];
+            }
+            server = new MidiDeviceServer(mMidiManager, inputPortReceivers,
+                    deviceInfo.getOutputPortCount());
+            server.setDeviceInfo(deviceInfo);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in IMidiManager.getServiceDeviceInfo");
+            server = null;
+        }
+        mServer = server;
+   }
+
+    /**
+     * Returns an array of {@link MidiReceiver} for the device's input ports.
+     * Subclasses must override this to provide the receivers which will receive
+     * data sent to the device's input ports. An empty array or null should be returned if
+     * the device has no input ports.
+     * @return array of MidiReceivers
+     */
+    abstract public MidiReceiver[] getInputPortReceivers();
+
+    /**
+     * Returns an array of {@link MidiReceiver} for the device's output ports.
+     * These can be used to send data out the device's output ports.
+     * @return array of MidiReceivers
+     */
+    public MidiReceiver[] getOutputPortReceivers() {
+        if (mServer == null) {
+            return null;
+        } else {
+            return mServer.getOutputPortReceivers();
+        }
+    }
+
+    /**
+     * returns the {@link MidiDeviceInfo} instance for this service
+     * @return our MidiDeviceInfo
+     */
+    public MidiDeviceInfo getDeviceInfo() {
+        return mDeviceInfo;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) {
+             return mServer.getBinderInterface().asBinder();
+        } else {
+             return null;
+       }
+    }
+}
diff --git a/media/java/android/media/midi/MidiDispatcher.java b/media/java/android/media/midi/MidiDispatcher.java
new file mode 100644
index 0000000..a5193f1
--- /dev/null
+++ b/media/java/android/media/midi/MidiDispatcher.java
@@ -0,0 +1,85 @@
+/*
+ * 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.media.midi;
+
+import java.io.IOException;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Utility class for dispatching MIDI data to a list of {@link MidiReceiver}s.
+ * This class subclasses {@link MidiReceiver} and dispatches any data it receives
+ * to its receiver list. Any receivers that throw an exception upon receiving data will
+ * be automatically removed from the receiver list, but no IOException will be returned
+ * from the dispatcher's {@link #receive} in that case.
+ *
+ * CANDIDATE FOR PUBLIC API
+ * @hide
+ */
+public final class MidiDispatcher extends MidiReceiver {
+
+    private final CopyOnWriteArrayList<MidiReceiver> mReceivers
+            = new CopyOnWriteArrayList<MidiReceiver>();
+
+    private final MidiSender mSender = new MidiSender() {
+        /**
+         * Called to connect a {@link MidiReceiver} to the sender
+         *
+         * @param receiver the receiver to connect
+         */
+        public void connect(MidiReceiver receiver) {
+            mReceivers.add(receiver);
+        }
+
+        /**
+         * Called to disconnect a {@link MidiReceiver} from the sender
+         *
+         * @param receiver the receiver to disconnect
+         */
+        public void disconnect(MidiReceiver receiver) {
+            mReceivers.remove(receiver);
+        }
+    };
+
+    /**
+     * Returns whether this dispatcher contains any receivers.
+     * @return true if the receiver list is not empty
+     */
+    public boolean hasReceivers() {
+        return mReceivers.size() > 0;
+    }
+
+    /**
+     * Returns a {@link MidiSender} which is used to add and remove {@link MidiReceiver}s
+     * to the dispatcher's receiver list.
+     * @return the dispatcher's MidiSender
+     */
+    public MidiSender getSender() {
+        return mSender;
+    }
+
+    @Override
+    public void receive(byte[] msg, int offset, int count, long timestamp) throws IOException {
+       for (MidiReceiver receiver : mReceivers) {
+            try {
+                receiver.receive(msg, offset, count, timestamp);
+            } catch (IOException e) {
+                // if the receiver fails we remove the receiver but do not propogate the exception
+                mReceivers.remove(receiver);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java
index 730d364..8674969 100644
--- a/media/java/android/media/midi/MidiInputPort.java
+++ b/media/java/android/media/midi/MidiInputPort.java
@@ -16,10 +16,16 @@
 
 package android.media.midi;
 
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
 
 import libcore.io.IoUtils;
 
+import java.io.Closeable;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
@@ -29,52 +35,93 @@
  * CANDIDATE FOR PUBLIC API
  * @hide
  */
-public class MidiInputPort extends MidiPort implements MidiReceiver {
+public final class MidiInputPort extends MidiReceiver implements Closeable {
+    private static final String TAG = "MidiInputPort";
 
+    private IMidiDeviceServer mDeviceServer;
+    private final IBinder mToken;
+    private final int mPortNumber;
     private final FileOutputStream mOutputStream;
 
-    // buffer to use for sending messages out our output stream
-    private final byte[] mBuffer = new byte[MAX_PACKET_SIZE];
+    private final CloseGuard mGuard = CloseGuard.get();
+    private boolean mIsClosed;
 
-  /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
-        super(portNumber);
+    // buffer to use for sending data out our output stream
+    private final byte[] mBuffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
+
+    /* package */ MidiInputPort(IMidiDeviceServer server, IBinder token,
+            ParcelFileDescriptor pfd, int portNumber) {
+        mDeviceServer = server;
+        mToken = token;
+        mPortNumber = portNumber;
         mOutputStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
+        mGuard.open("close");
+    }
+
+    /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
+        this(null, null, pfd, portNumber);
     }
 
     /**
-     * Writes a MIDI message to the input port
+     * Returns the port number of this port
      *
-     * @param msg byte array containing the message
-     * @param offset offset of first byte of the message in msg byte array
-     * @param count size of the message in bytes
-     * @param timestamp future time to post the message (based on
+     * @return the port's port number
+     */
+    public final int getPortNumber() {
+        return mPortNumber;
+    }
+
+    /**
+     * Writes MIDI data to the input port
+     *
+     * @param msg byte array containing the data
+     * @param offset offset of first byte of the data in msg byte array
+     * @param count size of the data in bytes
+     * @param timestamp future time to post the data (based on
      *                  {@link java.lang.System#nanoTime}
      */
-    public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
+    public void receive(byte[] msg, int offset, int count, long timestamp) throws IOException {
         assert(offset >= 0 && count >= 0 && offset + count <= msg.length);
 
         synchronized (mBuffer) {
-            try {
-                while (count > 0) {
-                    int length = packMessage(msg, offset, count, timestamp, mBuffer);
-                    mOutputStream.write(mBuffer, 0, length);
-                    int sent = getMessageSize(mBuffer, length);
-                    assert(sent >= 0 && sent <= length);
+            while (count > 0) {
+                int length = MidiPortImpl.packMessage(msg, offset, count, timestamp, mBuffer);
+                mOutputStream.write(mBuffer, 0, length);
+                int sent = MidiPortImpl.getMessageSize(mBuffer, length);
+                assert(sent >= 0 && sent <= length);
 
-                    offset += sent;
-                    count -= sent;
-                }
-            } catch (IOException e) {
-                IoUtils.closeQuietly(mOutputStream);
-                // report I/O failure
-                onIOException();
-                throw e;
+                offset += sent;
+                count -= sent;
             }
         }
     }
 
     @Override
     public void close() throws IOException {
-        mOutputStream.close();
+        synchronized (mGuard) {
+            if (mIsClosed) return;
+            mGuard.close();
+            mOutputStream.close();
+            if (mDeviceServer != null) {
+                try {
+                    mDeviceServer.closePort(mToken);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException in MidiInputPort.close()");
+                }
+            }
+            mIsClosed = true;
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mGuard.warnIfOpen();
+            // not safe to make binder calls from finalize()
+            mDeviceServer = null;
+            close();
+        } finally {
+            super.finalize();
+        }
     }
 }
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index a502e3e..d7b8c57 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -16,7 +16,11 @@
 
 package android.media.midi;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ServiceInfo;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Bundle;
@@ -38,7 +42,7 @@
  * CANDIDATE FOR PUBLIC API
  * @hide
  */
-public class MidiManager {
+public final class MidiManager {
     private static final String TAG = "MidiManager";
 
     private final Context mContext;
@@ -49,7 +53,7 @@
         new HashMap<DeviceCallback,DeviceListener>();
 
     // Binder stub for receiving device notifications from MidiService
-    private class DeviceListener extends IMidiListener.Stub {
+    private class DeviceListener extends IMidiDeviceListener.Stub {
         private final DeviceCallback mCallback;
         private final Handler mHandler;
 
@@ -88,22 +92,33 @@
     /**
      * Callback class used for clients to receive MIDI device added and removed notifications
      */
-    public static class DeviceCallback {
+    abstract public static class DeviceCallback {
         /**
          * Called to notify when a new MIDI device has been added
          *
          * @param device a {@link MidiDeviceInfo} for the newly added device
          */
-        public void onDeviceAdded(MidiDeviceInfo device) {
-        }
+        abstract public void onDeviceAdded(MidiDeviceInfo device);
 
         /**
          * Called to notify when a MIDI device has been removed
          *
          * @param device a {@link MidiDeviceInfo} for the removed device
          */
-        public void onDeviceRemoved(MidiDeviceInfo device) {
-        }
+        abstract public void onDeviceRemoved(MidiDeviceInfo device);
+    }
+
+    /**
+     * Callback class used for receiving the results of {@link #openDevice}
+     */
+    abstract public static class DeviceOpenCallback {
+        /**
+         * Called to respond to a {@link #openDevice} request
+         *
+         * @param deviceInfo the {@link MidiDeviceInfo} for the device to open
+         * @param device a {@link MidiDevice} for opened device, or null if opening failed
+         */
+        abstract public void onDeviceOpened(MidiDeviceInfo deviceInfo, MidiDevice device);
     }
 
     /**
@@ -163,33 +178,85 @@
         }
     }
 
+    private void sendOpenDeviceResponse(final MidiDeviceInfo deviceInfo, final MidiDevice device,
+            final DeviceOpenCallback callback, Handler handler) {
+        if (handler != null) {
+            handler.post(new Runnable() {
+                    @Override public void run() {
+                        callback.onDeviceOpened(deviceInfo, device);
+                    }
+                });
+        } else {
+            callback.onDeviceOpened(deviceInfo, device);
+        }
+    }
+
     /**
      * Opens a MIDI device for reading and writing.
      *
      * @param deviceInfo a {@link android.media.midi.MidiDeviceInfo} to open
-     * @return a {@link MidiDevice} object for the device
+     * @param callback a {@link #DeviceOpenCallback} to be called to receive the result
+     * @param handler the {@link android.os.Handler Handler} that will be used for delivering
+     *                the result. If handler is null, then the thread used for the
+     *                callback is unspecified.
      */
-    public MidiDevice openDevice(MidiDeviceInfo deviceInfo) {
+    public void openDevice(MidiDeviceInfo deviceInfo, DeviceOpenCallback callback,
+            Handler handler) {
+        MidiDevice device = null;
         try {
             IMidiDeviceServer server = mService.openDevice(mToken, deviceInfo);
             if (server == null) {
-                Log.e(TAG, "could not open device " + deviceInfo);
-                return null;
+                ServiceInfo serviceInfo = (ServiceInfo)deviceInfo.getProperties().getParcelable(
+                        MidiDeviceInfo.PROPERTY_SERVICE_INFO);
+                if (serviceInfo == null) {
+                    Log.e(TAG, "no ServiceInfo for " + deviceInfo);
+                } else {
+                    Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
+                    intent.setComponent(new ComponentName(serviceInfo.packageName,
+                            serviceInfo.name));
+                    final MidiDeviceInfo deviceInfoF = deviceInfo;
+                    final DeviceOpenCallback callbackF = callback;
+                    final Handler handlerF = handler;
+                    if (mContext.bindService(intent,
+                        new ServiceConnection() {
+                            @Override
+                            public void onServiceConnected(ComponentName name, IBinder binder) {
+                                IMidiDeviceServer server =
+                                        IMidiDeviceServer.Stub.asInterface(binder);
+                                MidiDevice device = new MidiDevice(deviceInfoF, server, mContext, this);
+                                sendOpenDeviceResponse(deviceInfoF, device, callbackF, handlerF);
+                            }
+
+                            @Override
+                            public void onServiceDisconnected(ComponentName name) {
+                                // FIXME - anything to do here?
+                            }
+                        },
+                        Context.BIND_AUTO_CREATE))
+                    {
+                        // return immediately to avoid calling sendOpenDeviceResponse below
+                        return;
+                    } else {
+                        Log.e(TAG, "Unable to bind  service: " + intent);
+                    }
+                }
+            } else {
+                device = new MidiDevice(deviceInfo, server);
             }
-            return new MidiDevice(deviceInfo, server);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in openDevice");
         }
-        return null;
+        sendOpenDeviceResponse(deviceInfo, device, callback, handler);
     }
 
     /** @hide */
-    public MidiDeviceServer createDeviceServer(int numInputPorts, int numOutputPorts,
-            Bundle properties, boolean isPrivate, int type) {
+    public MidiDeviceServer createDeviceServer(MidiReceiver[] inputPortReceivers,
+            int numOutputPorts, Bundle properties, int type) {
         try {
-            MidiDeviceServer server = new MidiDeviceServer(mService);
+            MidiDeviceServer server = new MidiDeviceServer(mService, inputPortReceivers,
+                    numOutputPorts);
             MidiDeviceInfo deviceInfo = mService.registerDeviceServer(server.getBinderInterface(),
-                    numInputPorts, numOutputPorts, properties, isPrivate, type);
+                    inputPortReceivers.length, numOutputPorts, properties, type);
             if (deviceInfo == null) {
                 Log.e(TAG, "registerVirtualDevice failed");
                 return null;
@@ -201,21 +268,4 @@
             return null;
         }
     }
-
-    /**
-     * Creates a new MIDI virtual device.
-     *
-     * @param numInputPorts number of input ports for the virtual device
-     * @param numOutputPorts number of output ports for the virtual device
-     * @param properties a {@link android.os.Bundle} containing properties describing the device
-     * @param isPrivate true if this device should only be visible and accessible to apps
-     *                  with the same UID as the caller
-     * @return a {@link MidiDeviceServer} object to locally represent the device
-     */
-    public MidiDeviceServer createDeviceServer(int numInputPorts, int numOutputPorts,
-            Bundle properties, boolean isPrivate) {
-        return createDeviceServer(numInputPorts, numOutputPorts, properties,
-                isPrivate, MidiDeviceInfo.TYPE_VIRTUAL);
-    }
-
 }
diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java
index 83ddeeb..b31cdd3 100644
--- a/media/java/android/media/midi/MidiOutputPort.java
+++ b/media/java/android/media/midi/MidiOutputPort.java
@@ -16,14 +16,18 @@
 
 package android.media.midi;
 
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.util.Log;
 
+import dalvik.system.CloseGuard;
+
 import libcore.io.IoUtils;
 
+import java.io.Closeable;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.util.ArrayList;
 
 /**
  * This class is used for receiving data from a port on a MIDI device
@@ -31,23 +35,24 @@
  * CANDIDATE FOR PUBLIC API
  * @hide
  */
-public class MidiOutputPort extends MidiPort implements MidiSender {
+public final class MidiOutputPort extends MidiSender implements Closeable {
     private static final String TAG = "MidiOutputPort";
 
+    private IMidiDeviceServer mDeviceServer;
+    private final IBinder mToken;
+    private final int mPortNumber;
     private final FileInputStream mInputStream;
+    private final MidiDispatcher mDispatcher = new MidiDispatcher();
 
-    // array of receiver lists, indexed by port number
-    private final ArrayList<MidiReceiver> mReceivers = new ArrayList<MidiReceiver>();
-
-    private int mReceiverCount; // total number of receivers for all ports
+    private final CloseGuard mGuard = CloseGuard.get();
+    private boolean mIsClosed;
 
     // This thread reads MIDI events from a socket and distributes them to the list of
     // MidiReceivers attached to this device.
     private final Thread mThread = new Thread() {
         @Override
         public void run() {
-            byte[] buffer = new byte[MAX_PACKET_SIZE];
-            ArrayList<MidiReceiver> deadReceivers = new ArrayList<MidiReceiver>();
+            byte[] buffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
 
             try {
                 while (true) {
@@ -55,81 +60,85 @@
                     int count = mInputStream.read(buffer);
                     if (count < 0) {
                         break;
+                        // FIXME - inform receivers here?
                     }
 
-                    int offset = getMessageOffset(buffer, count);
-                    int size = getMessageSize(buffer, count);
-                    long timestamp = getMessageTimeStamp(buffer, count);
+                    int offset = MidiPortImpl.getMessageOffset(buffer, count);
+                    int size = MidiPortImpl.getMessageSize(buffer, count);
+                    long timestamp = MidiPortImpl.getMessageTimeStamp(buffer, count);
 
-                    synchronized (mReceivers) {
-                        for (int i = 0; i < mReceivers.size(); i++) {
-                            MidiReceiver receiver = mReceivers.get(i);
-                            try {
-                                receiver.post(buffer, offset, size, timestamp);
-                            } catch (IOException e) {
-                                Log.e(TAG, "post failed");
-                                deadReceivers.add(receiver);
-                            }
-                        }
-                        // remove any receivers that failed
-                        if (deadReceivers.size() > 0) {
-                            for (MidiReceiver receiver: deadReceivers) {
-                                mReceivers.remove(receiver);
-                                mReceiverCount--;
-                            }
-                            deadReceivers.clear();
-                        }
-                        // exit if we have no receivers left
-                        if (mReceiverCount == 0) {
-                            break;
-                        }
-                    }
+                    // dispatch to all our receivers
+                    mDispatcher.receive(buffer, offset, size, timestamp);
                 }
             } catch (IOException e) {
-                // report I/O failure
+                // FIXME report I/O failure?
                 Log.e(TAG, "read failed");
             } finally {
                 IoUtils.closeQuietly(mInputStream);
-                onIOException();
             }
         }
     };
 
-  /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
-        super(portNumber);
+    /* package */ MidiOutputPort(IMidiDeviceServer server, IBinder token,
+            ParcelFileDescriptor pfd, int portNumber) {
+        mDeviceServer = server;
+        mToken = token;
+        mPortNumber = portNumber;
         mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        mThread.start();
+        mGuard.open("close");
+    }
+
+    /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
+        this(null, null, pfd, portNumber);
     }
 
     /**
-     * Connects a {@link MidiReceiver} to the output port to allow receiving
-     * MIDI messages from the port.
+     * Returns the port number of this port
      *
-     * @param receiver the receiver to connect
+     * @return the port's port number
      */
+    public final int getPortNumber() {
+        return mPortNumber;
+    }
+
+    @Override
     public void connect(MidiReceiver receiver) {
-        synchronized (mReceivers) {
-            mReceivers.add(receiver);
-            if (mReceiverCount++ == 0) {
-                mThread.start();
-            }
-        }
+        mDispatcher.getSender().connect(receiver);
     }
 
-    /**
-     * Disconnects a {@link MidiReceiver} from the output port.
-     *
-     * @param receiver the receiver to connect
-     */
+    @Override
     public void disconnect(MidiReceiver receiver) {
-        synchronized (mReceivers) {
-            if (mReceivers.remove(receiver)) {
-                mReceiverCount--;
-            }
-        }
+        mDispatcher.getSender().disconnect(receiver);
     }
 
     @Override
     public void close() throws IOException {
-        mInputStream.close();
+        synchronized (mGuard) {
+            if (mIsClosed) return;
+
+            mGuard.close();
+            mInputStream.close();
+            if (mDeviceServer != null) {
+                try {
+                    mDeviceServer.closePort(mToken);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException in MidiOutputPort.close()");
+                }
+            }
+            mIsClosed = true;
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mGuard.warnIfOpen();
+            // not safe to make binder calls from finalize()
+            mDeviceServer = null;
+            close();
+        } finally {
+            super.finalize();
+        }
     }
 }
diff --git a/media/java/android/media/midi/MidiPort.java b/media/java/android/media/midi/MidiPortImpl.java
similarity index 70%
rename from media/java/android/media/midi/MidiPort.java
rename to media/java/android/media/midi/MidiPortImpl.java
index 3aa03f2..5795045 100644
--- a/media/java/android/media/midi/MidiPort.java
+++ b/media/java/android/media/midi/MidiPortImpl.java
@@ -16,31 +16,20 @@
 
 package android.media.midi;
 
-import java.io.Closeable;
-
 /**
- * This class represents a MIDI input or output port.
- * Base class for {@link MidiInputPort} and {@link MidiOutputPort}
- *
- * CANDIDATE FOR PUBLIC API
- * @hide
+ * This class contains utilities for socket communication between a
+ * MidiInputPort and MidiOutputPort
  */
-abstract public class MidiPort implements Closeable {
+/* package */ class MidiPortImpl {
     private static final String TAG = "MidiPort";
 
-    private final int mPortNumber;
-
     /**
      * Maximum size of a packet that can pass through our ParcelFileDescriptor.
-     * For internal use only. Implementation details may change in the future.
-     * @hide
      */
     public static final int MAX_PACKET_SIZE = 1024;
 
     /**
      * size of message timestamp in bytes
-     * For internal use only. Implementation details may change in the future.
-     * @hide
      */
     private static final int TIMESTAMP_SIZE = 8;
 
@@ -49,29 +38,6 @@
      */
     public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
 
-
-  /* package */ MidiPort(int portNumber) {
-        mPortNumber = portNumber;
-    }
-
-    /**
-     * Returns the port number of this port
-     *
-     * @return the port's port number
-     */
-    public final int getPortNumber() {
-        return mPortNumber;
-    }
-
-    /**
-     * Called when an IOExeption occurs while sending or receiving data.
-     * Subclasses can override to be notified of such errors
-     *
-     * @hide
-     */
-     public void onIOException() {
-     }
-
     /**
      * Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor
      *
@@ -80,9 +46,6 @@
      * timestamp is message timestamp to pack
      * dest is buffer to pack into
      * returns size of packed message
-     *
-     * For internal use only. Implementation details may change in the future.
-     * @hide
      */
     public static int packMessage(byte[] message, int offset, int size, long timestamp,
             byte[] dest) {
@@ -104,9 +67,6 @@
     /**
      * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
      * returns the offset of the MIDI message in packed buffer
-     *
-     * For internal use only. Implementation details may change in the future.
-     * @hide
      */
     public static int getMessageOffset(byte[] buffer, int bufferLength) {
         // message is at the beginning
@@ -116,9 +76,6 @@
     /**
      * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
      * returns size of MIDI data in packed buffer
-     *
-     * For internal use only. Implementation details may change in the future.
-     * @hide
      */
     public static int getMessageSize(byte[] buffer, int bufferLength) {
         // message length is total buffer length minus size of the timestamp
@@ -128,9 +85,6 @@
     /**
      * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
      * unpacks timestamp from packed buffer
-     *
-     * For internal use only. Implementation details may change in the future.
-     * @hide
      */
     public static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
         // timestamp is at end of the packet
diff --git a/media/java/android/media/midi/MidiReceiver.java b/media/java/android/media/midi/MidiReceiver.java
index 64c0c07..674c974 100644
--- a/media/java/android/media/midi/MidiReceiver.java
+++ b/media/java/android/media/midi/MidiReceiver.java
@@ -24,7 +24,7 @@
  * CANDIDATE FOR PUBLIC API
  * @hide
  */
-public interface MidiReceiver {
+abstract public class MidiReceiver {
     /**
      * Called to pass MIDI data to the receiver.
      *
@@ -32,7 +32,7 @@
      * The msg bytes should be copied by the receiver rather than retaining a reference
      * to this parameter.
      * Also, modifying the contents of the msg array parameter may result in other receivers
-     * in the same application receiving incorrect values in their post() method.
+     * in the same application receiving incorrect values in their receive() method.
      *
      * @param msg a byte array containing the MIDI data
      * @param offset the offset of the first byte of the data in the byte array
@@ -40,5 +40,6 @@
      * @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
      * @throws IOException
      */
-    public void post(byte[] msg, int offset, int count, long timestamp) throws IOException;
+    abstract public void receive(byte[] msg, int offset, int count, long timestamp)
+            throws IOException;
 }
diff --git a/media/java/android/media/midi/MidiSender.java b/media/java/android/media/midi/MidiSender.java
index 4550476..9285973 100644
--- a/media/java/android/media/midi/MidiSender.java
+++ b/media/java/android/media/midi/MidiSender.java
@@ -23,18 +23,18 @@
  * CANDIDATE FOR PUBLIC API
  * @hide
  */
-public interface MidiSender {
+abstract public class MidiSender {
     /**
      * Called to connect a {@link MidiReceiver} to the sender
      *
      * @param receiver the receiver to connect
      */
-    public void connect(MidiReceiver receiver);
+    abstract public void connect(MidiReceiver receiver);
 
     /**
      * Called to disconnect a {@link MidiReceiver} from the sender
      *
      * @param receiver the receiver to disconnect
      */
-    public void disconnect(MidiReceiver receiver);
+    abstract public void disconnect(MidiReceiver receiver);
 }
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index cf69b8f..b247493 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -95,6 +95,9 @@
     void setBufferFormat(int format) { mFormat = format; }
     int getBufferFormat() { return mFormat; }
 
+    void setBufferDataspace(android_dataspace dataSpace) { mDataSpace = dataSpace; }
+    android_dataspace getBufferDataspace() { return mDataSpace; }
+
     void setBufferWidth(int width) { mWidth = width; }
     int getBufferWidth() { return mWidth; }
 
@@ -111,6 +114,7 @@
     jobject mWeakThiz;
     jclass mClazz;
     int mFormat;
+    android_dataspace mDataSpace;
     int mWidth;
     int mHeight;
 };
@@ -263,29 +267,6 @@
     env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast<jlong>(buffer));
 }
 
-// Some formats like JPEG defined with different values between android.graphics.ImageFormat and
-// graphics.h, need convert to the one defined in graphics.h here.
-static int Image_getPixelFormat(JNIEnv* env, int format)
-{
-    int jpegFormat;
-    jfieldID fid;
-
-    ALOGV("%s: format = 0x%x", __FUNCTION__, format);
-
-    jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
-    ALOG_ASSERT(imageFormatClazz != NULL);
-
-    fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
-    jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);
-
-    // Translate the JPEG to BLOB for camera purpose.
-    if (format == jpegFormat) {
-        format = HAL_PIXEL_FORMAT_BLOB;
-    }
-
-    return format;
-}
-
 static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride)
 {
     ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
@@ -483,7 +464,7 @@
 }
 
 static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
-        int32_t readerFormat)
+        int32_t halReaderFormat)
 {
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
     ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx);
@@ -493,7 +474,7 @@
 
     int32_t fmt = buffer->flexFormat;
 
-    fmt = applyFormatOverrides(fmt, readerFormat);
+    fmt = applyFormatOverrides(fmt, halReaderFormat);
 
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
@@ -543,7 +524,7 @@
 }
 
 static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
-        int32_t readerFormat)
+        int32_t halReaderFormat)
 {
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
     ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
@@ -553,7 +534,7 @@
 
     int32_t fmt = buffer->flexFormat;
 
-    fmt = applyFormatOverrides(fmt, readerFormat);
+    fmt = applyFormatOverrides(fmt, halReaderFormat);
 
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
@@ -682,11 +663,16 @@
 {
     status_t res;
     int nativeFormat;
+    android_dataspace nativeDataspace;
 
     ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
           __FUNCTION__, width, height, format, maxImages);
 
-    nativeFormat = Image_getPixelFormat(env, format);
+    PublicFormat publicFormat = static_cast<PublicFormat>(format);
+    nativeFormat = android_view_Surface_mapPublicFormatToHalFormat(
+        publicFormat);
+    nativeDataspace = android_view_Surface_mapPublicFormatToHalDataspace(
+        publicFormat);
 
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
@@ -710,10 +696,11 @@
     consumer->setFrameAvailableListener(ctx);
     ImageReader_setNativeContext(env, thiz, ctx);
     ctx->setBufferFormat(nativeFormat);
+    ctx->setBufferDataspace(nativeDataspace);
     ctx->setBufferWidth(width);
     ctx->setBufferHeight(height);
 
-    // Set the width/height/format to the CpuConsumer
+    // Set the width/height/format/dataspace to the CpuConsumer
     res = consumer->setDefaultBufferSize(width, height);
     if (res != OK) {
         jniThrowException(env, "java/lang/IllegalStateException",
@@ -725,6 +712,12 @@
         jniThrowException(env, "java/lang/IllegalStateException",
                           "Failed to set CpuConsumer buffer format");
     }
+    res = consumer->setDefaultBufferDataSpace(nativeDataspace);
+    if (res != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set CpuConsumer buffer dataSpace");
+    }
+
 }
 
 static void ImageReader_close(JNIEnv* env, jobject thiz)
@@ -884,6 +877,8 @@
 static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int readerFormat)
 {
     int rowStride, pixelStride;
+    PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
+
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
 
     CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
@@ -893,10 +888,11 @@
         jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
     }
 
-    readerFormat = Image_getPixelFormat(env, readerFormat);
+    int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
+        publicReaderFormat);
 
-    rowStride = Image_imageGetRowStride(env, buffer, idx, readerFormat);
-    pixelStride = Image_imageGetPixelStride(env, buffer, idx, readerFormat);
+    rowStride = Image_imageGetRowStride(env, buffer, idx, halReaderFormat);
+    pixelStride = Image_imageGetPixelStride(env, buffer, idx, halReaderFormat);
 
     jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
             gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
@@ -909,6 +905,7 @@
     uint8_t *base = NULL;
     uint32_t size = 0;
     jobject byteBuffer;
+    PublicFormat readerPublicFormat = static_cast<PublicFormat>(readerFormat);
 
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
 
@@ -918,10 +915,11 @@
         jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
     }
 
-    readerFormat = Image_getPixelFormat(env, readerFormat);
+    int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
+            readerPublicFormat);
 
     // Create byteBuffer from native buffer
-    Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerFormat);
+    Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerHalFormat);
 
     if (size > static_cast<uint32_t>(INT32_MAX)) {
         // Byte buffer have 'int capacity', so check the range
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 1cf589d..16758d0 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -215,7 +215,7 @@
 status_t JMediaCodec::setCallback(jobject cb) {
     if (cb != NULL) {
         if (mCallbackNotification == NULL) {
-            mCallbackNotification = new AMessage(kWhatCallbackNotify, id());
+            mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
         }
     } else {
         mCallbackNotification.clear();
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 93138fa..2f6bbf4 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -40,7 +40,6 @@
 struct fields_t {
     jfieldID context;
     jclass bitmapClazz;  // Must be a global ref
-    jfieldID nativeBitmap;
     jmethodID createBitmapMethod;
     jmethodID createScaledBitmapMethod;
     jclass configClazz;  // Must be a global ref
@@ -282,8 +281,7 @@
         return NULL;
     }
 
-    SkBitmap *bitmap =
-            (SkBitmap *) env->GetLongField(jBitmap, fields.nativeBitmap);
+    SkBitmap *bitmap = GraphicsJNI::getSkBitmap(env, jBitmap);
 
     bitmap->lockPixels();
     rotate((uint16_t*)bitmap->getPixels(),
@@ -421,10 +419,6 @@
     if (fields.createScaledBitmapMethod == NULL) {
         return;
     }
-    fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "J");
-    if (fields.nativeBitmap == NULL) {
-        return;
-    }
 
     jclass configClazz = env->FindClass("android/graphics/Bitmap$Config");
     if (configClazz == NULL) {
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index a73209b..1205f9d 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -626,7 +626,7 @@
        goto error;
     }
 
-    if ((numChannels < 1) || (numChannels > 2)) {
+    if ((numChannels < 1) || (numChannels > 8)) {
         ALOGE("Sample channel count (%d) out of range", numChannels);
         status = BAD_VALUE;
         goto error;
@@ -689,8 +689,10 @@
         size_t frameCount = 0;
 
         if (loop) {
-            frameCount = sample->size()/numChannels/
-                ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
+            const audio_format_t format = sample->format();
+            const size_t frameSize = audio_is_linear_pcm(format)
+                    ? numChannels * audio_bytes_per_sample(format) : 1;
+            frameCount = sample->size() / frameSize;
         }
 
 #ifndef USE_SHARED_MEM_BUFFER
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 9d9cbdf..d19cd91 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -72,8 +72,8 @@
     volatile int32_t    mRefCount;
     uint16_t            mSampleID;
     uint16_t            mSampleRate;
-    uint8_t             mState : 3;
-    uint8_t             mNumChannels : 2;
+    uint8_t             mState;
+    uint8_t             mNumChannels;
     audio_format_t      mFormat;
     int                 mFd;
     int64_t             mOffset;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 3cae19d..d756d05 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -161,8 +161,7 @@
         assertFalse(request.isEmpty());
         assertFalse(metadata.isEmpty());
         if (needStream) {
-            int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20,
-                    /* ignored */30, mSurface);
+            int streamId = mCameraUser.createStream(mSurface);
             assertEquals(0, streamId);
             request.addTarget(mSurface);
         }
@@ -235,12 +234,11 @@
 
     @SmallTest
     public void testCreateStream() throws Exception {
-        int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, /* ignored */30,
-                mSurface);
+        int streamId = mCameraUser.createStream(mSurface);
         assertEquals(0, streamId);
 
         assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface));
+                mCameraUser.createStream(mSurface));
 
         assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
     }
@@ -257,20 +255,18 @@
     public void testCreateStreamTwo() throws Exception {
 
         // Create first stream
-        int streamId = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0,
-                mSurface);
+        int streamId = mCameraUser.createStream(mSurface);
         assertEquals(0, streamId);
 
         assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface));
+                mCameraUser.createStream(mSurface));
 
         // Create second stream with a different surface.
         SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
         surfaceTexture.setDefaultBufferSize(640, 480);
         Surface surface2 = new Surface(surfaceTexture);
 
-        int streamId2 = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0,
-                surface2);
+        int streamId2 = mCameraUser.createStream(surface2);
         assertEquals(1, streamId2);
 
         // Clean up streams
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index ea32edc..ddb01a0 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -27,7 +27,7 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
     if (NULL == bm) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
@@ -64,7 +64,7 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
     if (NULL == bm) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
@@ -87,7 +87,7 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
     if (NULL == bm) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index a9d33dd..4d890c9 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -29,14 +29,6 @@
 
 public final class GLUtils {
 
-    /*
-     * We use a class initializer to allow the native code to cache some
-     * field offsets.
-     */
-    static {
-        nativeClassInit();
-    }
-
     private GLUtils() {
     }
 
@@ -275,8 +267,6 @@
      */
     native public static void setTracingLevel(int level);
 
-    native private static void nativeClassInit();
-
     native private static int native_getInternalFormat(Bitmap bitmap);
     native private static int native_getType(Bitmap bitmap);
     native private static int native_texImage2D(int target, int level, int internalformat,
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index b47b76e..40cd5e6 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -79,7 +79,7 @@
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> razy narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Zostanie on zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a66fc22..396fe4f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -371,24 +371,11 @@
     }
 
     private boolean isTrustDisabled(int userId) {
-        final DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
-                // TODO once UI is finalized
-                final boolean disabledByGlobalActions = false;
-                final boolean disabledBySettings = false;
-
-                // Don't allow trust agent if device is secured with a SIM PIN. This is here
-                // mainly because there's no other way to prompt the user to enter their SIM PIN
-                // once they get past the keyguard screen.
-                final boolean disabledBySimPin = isSimPinSecure();
-
-                final boolean disabledByDpm = (dpm.getKeyguardDisabledFeatures(null, userId)
-                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
-                return disabledByDpm || disabledByGlobalActions || disabledBySettings
-                        || disabledBySimPin;
-        }
-        return false;
+        // Don't allow trust agent if device is secured with a SIM PIN. This is here
+        // mainly because there's no other way to prompt the user to enter their SIM PIN
+        // once they get past the keyguard screen.
+        final boolean disabledBySimPin = isSimPinSecure();
+        return disabledBySimPin;
     }
 
     private boolean isFingerprintDisabled(int userId) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 0d03ed9..3a8216d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -354,6 +354,7 @@
 
             XmlSerializer serializer = Xml.newSerializer();
             serializer.setOutput(out, "utf-8");
+            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             serializer.startDocument(null, true);
             serializer.startTag(null, TAG_SETTINGS);
             serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
@@ -383,7 +384,7 @@
             }
 
         } catch (IOException e) {
-            Slog.w(LOG_TAG, "Failed to write settings, restoring backup", e);
+            Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", e);
             destination.failWrite(out);
         } finally {
             IoUtils.closeQuietly(out);
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
new file mode 100644
index 0000000..8ca5634
--- /dev/null
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -0,0 +1,46 @@
+<?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 -->
+<com.android.systemui.statusbar.policy.RemoteInputView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:theme="@style/systemui_theme_light"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:paddingStart="4dp"
+        android:paddingEnd="2dp"
+        android:paddingBottom="4dp"
+        android:paddingTop="2dp">
+
+    <view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText"
+            android:id="@+id/remote_input_text"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:singleLine="true"
+            android:imeOptions="actionSend" />
+
+    <ProgressBar
+            android:id="@+id/remote_input_progress"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom"
+            android:visibility="invisible"
+            android:indeterminate="true"
+            style="?android:attr/progressBarStyleHorizontal" />
+
+</com.android.systemui.statusbar.policy.RemoteInputView>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 905ccd9..d69cf29 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -44,7 +44,7 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Accubesparing inschakelen"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegmodus"</string>
+    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Scherm automatisch draaien"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPEN"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -144,7 +144,7 @@
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wifi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Geen simkaart."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth-tethering."</string>
-    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Vliegmodus."</string>
+    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Vliegtuigmodus."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Accu: <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systeeminstellingen."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Meldingen."</string>
@@ -172,10 +172,10 @@
     <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi ingeschakeld."</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobiel <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Accu: <xliff:g id="STATE">%s</xliff:g>."</string>
-    <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Vliegmodus uit."</string>
-    <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Vliegmodus aan."</string>
-    <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Vliegmodus uitgeschakeld."</string>
-    <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegmodus ingeschakeld."</string>
+    <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Vliegtuigmodus uit."</string>
+    <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Vliegtuigmodus aan."</string>
+    <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Vliegtuigmodus uitgeschakeld."</string>
+    <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegtuigmodus ingeschakeld."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Niet storen aan, alleen prioriteit."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Niet storen aan, geen onderbrekingen."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Niet storen uit."</string>
@@ -228,7 +228,7 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertshowcase"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Dagdroom"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegmodus"</string>
+    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegtuigmodus"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Niet storen"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Alleen prioriteit"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Geen onderbrekingen"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3b912bb4..07e0ef7 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -303,7 +303,7 @@
     <string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Inga avbrott. Inte ens alarm."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Inga avbrott"</string>
-    <string name="zen_important_interruptions" msgid="3477041776609757628">"Endast prioriterade avbrott"</string>
+    <string name="zen_important_interruptions" msgid="3477041776609757628">"Endast prioriterade samtal och aviseringar"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Nästa alarm är kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Nästa alarm är <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Alarmet kommer inte att höras kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 94f77c6..07fcb82 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -211,6 +211,11 @@
         <item name="android:colorControlActivated">@color/system_accent_color</item>
     </style>
 
+    <style name="systemui_theme_light" parent="@android:style/Theme.DeviceDefault.Light">
+        <item name="android:colorPrimary">@color/system_primary_color</item>
+        <item name="android:colorControlActivated">@color/system_accent_color</item>
+    </style>
+
     <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
         <item name="android:colorPrimary">@color/system_primary_color</item>
         <item name="android:colorControlActivated">@color/system_accent_color</item>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0168b95..275a6be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -172,7 +172,7 @@
     private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics";
 
     /** The stream type that the lock sounds are tied to. */
-    private int mMasterStreamType;
+    private int mUiSoundsStreamType;
 
     private AlarmManager mAlarmManager;
     private AudioManager mAudioManager;
@@ -1244,10 +1244,10 @@
             if (mAudioManager == null) {
                 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
                 if (mAudioManager == null) return;
-                mMasterStreamType = mAudioManager.getMasterStreamType();
+                mUiSoundsStreamType = mAudioManager.getUiSoundsStreamType();
             }
             // If the stream is muted, don't play the sound
-            if (mAudioManager.isStreamMute(mMasterStreamType)) return;
+            if (mAudioManager.isStreamMute(mUiSoundsStreamType)) return;
 
             mLockSoundStreamId = mLockSounds.play(soundId,
                     mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
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 925d17e..84544ff 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -33,7 +33,7 @@
     private static Method sPropertyMethod;
     static {
         try {
-            Class<?> c = Class.forName("android.view.GLES20Canvas");
+            Class<?> c = Class.forName("android.view.DisplayListCanvas");
             sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
             if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
         } catch (ClassNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3a812cc..8347a22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -24,6 +24,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.RemoteInput;
 import android.app.TaskStackBuilder;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -49,6 +50,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -59,6 +61,7 @@
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.Display;
@@ -97,6 +100,7 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
 import com.android.systemui.statusbar.policy.PreviewInflater;
+import com.android.systemui.statusbar.policy.RemoteInputView;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
@@ -116,6 +120,9 @@
     // STOPSHIP disable once we resolve b/18102199
     private static final boolean NOTIFICATION_CLICK_DEBUG = true;
 
+    public static final boolean ENABLE_REMOTE_INPUT =
+            Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.enable_remote_input", false);
+
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
     protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
@@ -409,6 +416,7 @@
                 @Override
                 public void run() {
                     for (StatusBarNotification sbn : notifications) {
+                        processForRemoteInput(sbn.getNotification());
                         addNotification(sbn, currentRanking);
                     }
                 }
@@ -423,6 +431,7 @@
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
+                        processForRemoteInput(sbn.getNotification());
                         Notification n = sbn.getNotification();
                         boolean isUpdate = mNotificationData.get(sbn.getKey()) != null
                                 || isHeadsUp(sbn.getKey());
@@ -1356,6 +1365,9 @@
                 (NotificationContentView) row.findViewById(R.id.expandedPublic);
 
         row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        if (ENABLE_REMOTE_INPUT) {
+            row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        }
 
         PendingIntent contentIntent = sbn.getNotification().contentIntent;
         if (contentIntent != null) {
@@ -1517,9 +1529,103 @@
         }
         row.setUserLocked(userLocked);
         row.setStatusBarNotification(entry.notification);
+        applyRemoteInput(entry);
         return true;
     }
 
+    /**
+     * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
+     * via first-class API.
+     *
+     * TODO: Remove once enough apps specify remote inputs on their own.
+     */
+    private void processForRemoteInput(Notification n) {
+        if (!ENABLE_REMOTE_INPUT) return;
+
+        if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
+                (n.actions == null || n.actions.length == 0)) {
+            Notification.Action viableAction = null;
+            Notification.WearableExtender we = new Notification.WearableExtender(n);
+
+            List<Notification.Action> actions = we.getActions();
+            final int numActions = actions.size();
+
+            for (int i = 0; i < numActions; i++) {
+                Notification.Action action = actions.get(i);
+                RemoteInput[] remoteInputs = action.getRemoteInputs();
+                for (RemoteInput ri : action.getRemoteInputs()) {
+                    if (ri.getAllowFreeFormInput()) {
+                        viableAction = action;
+                        break;
+                    }
+                }
+                if (viableAction != null) {
+                    break;
+                }
+            }
+
+            if (viableAction != null) {
+                Notification stripped = n.clone();
+                Notification.Builder.stripForDelivery(stripped);
+                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;
+
+                // Don't create the HUN input view for now because input doesn't work there yet.
+                // TODO: Enable once HUNs can take remote input correctly.
+                if (false) {
+                    stripped.extras.putBoolean("android.rebuild.hudView", true);
+                    stripped.headsUpContentView = null;
+                }
+
+                Notification rebuilt = Notification.Builder.rebuild(mContext, stripped);
+
+                n.actions = rebuilt.actions;
+                n.bigContentView = rebuilt.bigContentView;
+                n.headsUpContentView = rebuilt.headsUpContentView;
+                n.publicVersion = rebuilt.publicVersion;
+            }
+        }
+    }
+
+    private void applyRemoteInput(final Entry entry) {
+        if (!ENABLE_REMOTE_INPUT) return;
+
+        RemoteInput remoteInput = null;
+
+        // See if the notification has exactly one action and this action allows free-form input
+        // TODO: relax restrictions once we support more than one remote input action.
+        Notification.Action[] actions = entry.notification.getNotification().actions;
+        if (actions != null && actions.length == 1) {
+            if (actions[0].getRemoteInputs() != null) {
+                for (RemoteInput ri : actions[0].getRemoteInputs()) {
+                    if (ri.getAllowFreeFormInput()) {
+                        remoteInput = ri;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // See if we have somewhere to put that remote input
+        ViewGroup actionContainer = null;
+        if (remoteInput != null && entry.expandedBig != null) {
+            View actionContainerCandidate = entry.expandedBig
+                    .findViewById(com.android.internal.R.id.actions);
+            if (actionContainerCandidate instanceof ViewGroup) {
+                actionContainer = (ViewGroup) actionContainerCandidate;
+            }
+        }
+
+        if (actionContainer != null) {
+            actionContainer.removeAllViews();
+            actionContainer.addView(
+                    RemoteInputView.inflate(mContext, actionContainer, actions[0], remoteInput));
+        }
+    }
+
     public NotificationClicker makeClicker(PendingIntent intent, String notificationKey) {
         return new NotificationClicker(intent, notificationKey);
     }
@@ -2036,6 +2142,8 @@
         entry.row.setStatusBarNotification(notification);
         entry.row.notifyContentUpdated();
         entry.row.resetHeight();
+
+        applyRemoteInput(entry);
     }
 
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
@@ -2150,6 +2258,14 @@
     }
 
     public boolean isKeyguardSecure() {
+        if (mStatusBarKeyguardViewManager == null) {
+            // startKeyguard() hasn't been called yet, so we don't know.
+            // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
+            // value onVisibilityChanged().
+            Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
+                    new Throwable());
+            return false;
+        }
         return mStatusBarKeyguardViewManager.isSecure();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index acf7af9..0c21b20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -220,6 +220,7 @@
 
     public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
         mPhoneStatusBar = phoneStatusBar;
+        updateCameraVisibility(); // in case onFinishInflate() was called too early
     }
 
     private Intent getCameraIntent() {
@@ -231,6 +232,10 @@
     }
 
     private void updateCameraVisibility() {
+        if (mCameraImageView == null) {
+            // Things are not set up yet; reply hazy, ask again later
+            return;
+        }
         ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
                 PackageManager.MATCH_DEFAULT_ONLY,
                 mLockPatternUtils.getCurrentUser());
@@ -253,7 +258,7 @@
     private boolean isCameraDisabledByDpm() {
         final DevicePolicyManager dpm =
                 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
+        if (dpm != null && mPhoneStatusBar != null) {
             try {
                 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
                 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index eba7d9f..63bbf97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -115,7 +115,8 @@
 
     private void applyFocusableFlag(State state) {
         if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput
-                && state.bouncerShowing) {
+                && state.bouncerShowing
+                || BaseStatusBar.ENABLE_REMOTE_INPUT && state.statusBarExpanded) {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
new file mode 100644
index 0000000..7d721c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -0,0 +1,191 @@
+/*
+ * 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.policy;
+
+import com.android.systemui.R;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+/**
+ * Host for the remote input.
+ */
+public class RemoteInputView extends FrameLayout implements View.OnClickListener {
+
+    private static final String TAG = "RemoteInput";
+
+    private RemoteEditText mEditText;
+    private ProgressBar mProgressBar;
+    private PendingIntent mPendingIntent;
+    private RemoteInput mRemoteInput;
+    private Notification.Action mAction;
+
+    public RemoteInputView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mProgressBar = (ProgressBar) findViewById(R.id.remote_input_progress);
+
+        mEditText = (RemoteEditText) getChildAt(0);
+        mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+
+                // Check if this was the result of hitting the enter key
+                final boolean isSoftImeEvent = event == null
+                        && (actionId == EditorInfo.IME_ACTION_DONE
+                        || actionId == EditorInfo.IME_ACTION_NEXT
+                        || actionId == EditorInfo.IME_ACTION_SEND);
+                final boolean isKeyboardEnterKey = event != null
+                        && KeyEvent.isConfirmKey(event.getKeyCode())
+                        && event.getAction() == KeyEvent.ACTION_DOWN;
+
+                if (isSoftImeEvent || isKeyboardEnterKey) {
+                    sendRemoteInput();
+                    return true;
+                }
+                return false;
+            }
+        });
+        mEditText.setOnClickListener(this);
+        mEditText.setInnerFocusable(false);
+    }
+
+    private void sendRemoteInput() {
+        Bundle results = new Bundle();
+        results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
+        Intent fillInIntent = new Intent();
+        RemoteInput.addResultsToIntent(mAction.getRemoteInputs(), fillInIntent,
+                results);
+
+        mEditText.setEnabled(false);
+        mProgressBar.setVisibility(VISIBLE);
+
+        try {
+            mPendingIntent.send(mContext, 0, fillInIntent);
+        } catch (PendingIntent.CanceledException e) {
+            Log.i(TAG, "Unable to send remote input result", e);
+        }
+    }
+
+    public static RemoteInputView inflate(Context context, ViewGroup root,
+            Notification.Action action, RemoteInput remoteInput) {
+        RemoteInputView v = (RemoteInputView)
+                LayoutInflater.from(context).inflate(R.layout.remote_input, root, false);
+
+        v.mEditText.setHint(action.title);
+        v.mPendingIntent = action.actionIntent;
+        v.mRemoteInput = remoteInput;
+        v.mAction = action;
+
+        return v;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mEditText) {
+            if (!mEditText.isFocusable()) {
+                mEditText.setInnerFocusable(true);
+                InputMethodManager imm = InputMethodManager.getInstance();
+                if (imm != null) {
+                    imm.viewClicked(mEditText);
+                    imm.showSoftInput(mEditText, 0);
+                }
+            }
+        }
+    }
+
+    /**
+     * An EditText that changes appearance based on whether it's focusable and becomes
+     * un-focusable whenever the user navigates away from it or it becomes invisible.
+     */
+    public static class RemoteEditText extends EditText {
+
+        private final Drawable mBackground;
+
+        public RemoteEditText(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            mBackground = getBackground();
+        }
+
+        private void defocusIfNeeded() {
+            if (isFocusable() && isEnabled()) {
+                setInnerFocusable(false);
+            }
+        }
+
+        @Override
+        protected void onVisibilityChanged(View changedView, int visibility) {
+            super.onVisibilityChanged(changedView, visibility);
+
+            if (!isShown()) {
+                defocusIfNeeded();
+            }
+        }
+
+        @Override
+        protected void onFocusLost() {
+            super.onFocusLost();
+            defocusIfNeeded();
+        }
+
+        @Override
+        public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+            if (keyCode == KeyEvent.KEYCODE_BACK) {
+                defocusIfNeeded();
+            }
+            return super.onKeyPreIme(keyCode, event);
+        }
+
+
+        void setInnerFocusable(boolean focusable) {
+            setFocusableInTouchMode(focusable);
+            setFocusable(focusable);
+            setCursorVisible(focusable);
+
+            if (focusable) {
+                requestFocus();
+                setBackground(mBackground);
+            } else {
+                setBackground(null);
+            }
+
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 31264ee..51adaac 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -125,8 +125,6 @@
     private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15;
     private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 16;
 
-    // Pseudo stream type for master volume
-    private static final int STREAM_MASTER = -100;
     // Pseudo stream type for remote volume
     private static final int STREAM_REMOTE_MUSIC = -200;
 
@@ -154,10 +152,6 @@
     private int mLastRingerProgress = 0;
     private int mDemoIcon;
 
-    // True if we want to play tones on the system stream when the master stream is specified.
-    private final boolean mPlayMasterStreamTones;
-
-
     /** Volume panel content view */
     private final View mView;
     /** Dialog hosting the panel */
@@ -213,12 +207,6 @@
                 com.android.systemui.R.drawable.ic_ringer_audible,
                 com.android.systemui.R.drawable.ic_ringer_mute,
                 true),
-        // for now, use media resources for master volume
-        MasterStream(STREAM_MASTER,
-                R.string.volume_icon_description_media, //FIXME should have its own description
-                IC_AUDIO_VOL,
-                IC_AUDIO_VOL_MUTE,
-                false),
         RemoteStream(STREAM_REMOTE_MUSIC,
                 R.string.volume_icon_description_media, //FIXME should have its own description
                 com.android.systemui.R.drawable.ic_audio_remote,
@@ -249,7 +237,6 @@
         StreamResources.MediaStream,
         StreamResources.NotificationStream,
         StreamResources.AlarmStream,
-        StreamResources.MasterStream,
         StreamResources.RemoteStream
     };
 
@@ -371,15 +358,6 @@
         mSecondaryIconTransition = new SecondaryIconTransition();
         mIconPulser = new IconPulser(context);
 
-        // For now, only show master volume if master volume is supported
-        final Resources res = context.getResources();
-        final boolean useMasterVolume = res.getBoolean(R.bool.config_useMasterVolume);
-        if (useMasterVolume) {
-            for (int i = 0; i < STREAMS.length; i++) {
-                StreamResources streamRes = STREAMS[i];
-                streamRes.show = (streamRes.streamType == STREAM_MASTER);
-            }
-        }
         if (LOGD) Log.d(mTag, "new VolumePanel");
 
         mDisabledAlpha = 0.5f;
@@ -419,6 +397,7 @@
 
         mDialog.create();
 
+        final Resources res = context.getResources();
         window.setAttributes(getDialogLayoutParams(window, res));
 
         updateWidth();
@@ -447,16 +426,12 @@
         mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
 
-        if (mZenController != null && !useMasterVolume) {
+        if (mZenController != null) {
             mZenModeAvailable = mZenController.isZenAvailable();
             mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
             mZenController.addCallback(mZenCallback);
         }
 
-        final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
-        final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
-        mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
-
         registerReceiver();
     }
 
@@ -489,7 +464,6 @@
         pw.print("  mDisabledAlpha="); pw.println(mDisabledAlpha);
         pw.print("  mLastRingerMode="); pw.println(mLastRingerMode);
         pw.print("  mLastRingerProgress="); pw.println(mLastRingerProgress);
-        pw.print("  mPlayMasterStreamTones="); pw.println(mPlayMasterStreamTones);
         pw.print("  isShowing()="); pw.println(isShowing());
         pw.print("  mCallback="); pw.println(mCallback);
         pw.print("  sConfirmSafeVolumeDialog=");
@@ -576,9 +550,7 @@
     }
 
     private boolean isMuted(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            return mAudioManager.isMasterMute();
-        } else if (streamType == STREAM_REMOTE_MUSIC) {
+        if (streamType == STREAM_REMOTE_MUSIC) {
             // TODO do we need to support a distinct mute property for remote?
             return false;
         } else {
@@ -587,9 +559,7 @@
     }
 
     private int getStreamMaxVolume(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            return mAudioManager.getMasterMaxVolume();
-        } else if (streamType == STREAM_REMOTE_MUSIC) {
+        if (streamType == STREAM_REMOTE_MUSIC) {
             if (mStreamControls != null) {
                 StreamControl sc = mStreamControls.get(streamType);
                 if (sc != null && sc.controller != null) {
@@ -604,9 +574,7 @@
     }
 
     private int getStreamVolume(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            return mAudioManager.getLastAudibleMasterVolume();
-        } else if (streamType == STREAM_REMOTE_MUSIC) {
+        if (streamType == STREAM_REMOTE_MUSIC) {
             if (mStreamControls != null) {
                 StreamControl sc = mStreamControls.get(streamType);
                 if (sc != null && sc.controller != null) {
@@ -628,11 +596,7 @@
                 Log.w(mTag, "Adjusting remote volume without a controller!");
             }
         } else if (getStreamVolume(sc.streamType) != index) {
-            if (sc.streamType == STREAM_MASTER) {
-                mAudioManager.setMasterVolume(index, flags);
-            } else {
-                mAudioManager.setStreamVolume(sc.streamType, index, flags);
-            }
+            mAudioManager.setStreamVolume(sc.streamType, index, flags);
         }
     }
 
@@ -833,7 +797,7 @@
             sc.icon.setAlpha(mDisabledAlpha);
             sc.icon.setClickable(false);
         } else if (fixedVolume ||
-                (sc.streamType != mAudioManager.getMasterStreamType() && !isRinger && muted) ||
+                (sc.streamType != mAudioManager.getUiSoundsStreamType() && !isRinger && muted) ||
                 (sSafetyWarning != null)) {
             sc.seekbarView.setEnabled(false);
         } else {
@@ -977,10 +941,6 @@
         obtainMessage(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN).sendToTarget();
     }
 
-    public void postMasterVolumeChanged(int flags) {
-        postVolumeChanged(STREAM_MASTER, flags);
-    }
-
     public void postMuteChanged(int streamType, int flags) {
         if (hasMessages(MSG_VOLUME_CHANGED)) return;
         synchronized (this) {
@@ -992,10 +952,6 @@
         obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
     }
 
-    public void postMasterMuteChanged(int flags) {
-        postMuteChanged(STREAM_MASTER, flags);
-    }
-
     public void postDisplaySafeVolumeWarning(int flags) {
         if (hasMessages(MSG_DISPLAY_SAFE_VOLUME_WARNING)) return;
         obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, flags, 0).sendToTarget();
@@ -1192,9 +1148,7 @@
         if (!isShowing()) {
             int stream = (streamType == STREAM_REMOTE_MUSIC) ? -1 : streamType;
             // when the stream is for remote playback, use -1 to reset the stream type evaluation
-            if (stream != STREAM_MASTER) {
-                mAudioManager.forceVolumeControlStream(stream);
-            }
+            mAudioManager.forceVolumeControlStream(stream);
             mDialog.show();
             if (mCallback != null) {
                 mCallback.onVisible(true);
@@ -1360,16 +1314,6 @@
      * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
      */
     private ToneGenerator getOrCreateToneGenerator(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            // For devices that use the master volume setting only but still want to
-            // play a volume-changed tone, direct the master volume pseudostream to
-            // the system stream's tone generator.
-            if (mPlayMasterStreamTones) {
-                streamType = AudioManager.STREAM_SYSTEM;
-            } else {
-                return null;
-            }
-        }
         synchronized (this) {
             if (mToneGenerators[streamType] == null) {
                 try {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index f7f3bd8..7603c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -201,13 +201,8 @@
         }
 
         @Override
-        public void masterVolumeChanged(int flags) throws RemoteException {
-            mPanel.postMasterVolumeChanged(flags);
-        }
-
-        @Override
         public void masterMuteChanged(int flags) throws RemoteException {
-            mPanel.postMasterMuteChanged(flags);
+            // no-op
         }
 
         @Override
diff --git a/preloaded-classes b/preloaded-classes
index dee84f0..c8d8c5d 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1172,6 +1172,7 @@
 android.telecom.InCallService
 android.telephony.PhoneNumberUtils
 android.telephony.Rlog
+android.telephony.SignalStrength
 android.telephony.SubscriptionManager
 android.telephony.TelephonyManager
 android.text.AndroidBidi
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index ede63a9..c6afa2c 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -60,6 +60,7 @@
 
     boolean mReadAllowed = true;
     boolean mWriteAllowed = true;
+    boolean mAutoPadding = false;
     int mSelectedX;
     int mSelectedY;
     int mSelectedZ;
@@ -270,6 +271,17 @@
     }
 
     /**
+     * @hide
+     * Enable/Disable AutoPadding for Vec3 elements.
+     *
+     * @param useAutoPadding True: enable AutoPadding; flase: disable AutoPadding
+     *
+     */
+    public void setAutoPadding(boolean useAutoPadding) {
+        mAutoPadding = useAutoPadding;
+    }
+
+    /**
      * Get the size of the Allocation in bytes.
      *
      * @return size of the Allocation in bytes.
@@ -785,6 +797,7 @@
         copy1DRangeFromUnchecked(xoff, count, data);
     }
 
+
     /**
      * This is only intended to be used by auto-generated code reflected from
      * the RenderScript script files.
@@ -804,20 +817,6 @@
      *
      * @param xoff
      * @param yoff
-     * @param component_number
-     * @param fp
-     */
-    public void setFromFieldPacker(int xoff, int yoff, int component_number, FieldPacker fp) {
-        setFromFieldPacker(xoff, yoff, 0, component_number, fp);
-    }
-
-    /**
-     * @hide
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files.
-     *
-     * @param xoff
-     * @param yoff
      * @param zoff
      * @param component_number
      * @param fp
@@ -851,7 +850,7 @@
                                    component_number, data, data_length);
     }
 
-    private void data1DChecks(int off, int count, int len, int dataSize) {
+    private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
         mRS.validate();
         if(off < 0) {
             throw new RSIllegalArgumentException("Offset must be >= 0.");
@@ -863,8 +862,14 @@
             throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
                                                ", got " + count + " at offset " + off + ".");
         }
-        if(len < dataSize) {
-            throw new RSIllegalArgumentException("Array too small for allocation type.");
+        if(usePadding) {
+            if(len < dataSize / 4 * 3) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        } else {
+            if(len < dataSize) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
         }
     }
 
@@ -886,8 +891,14 @@
                                           Element.DataType dt, int arrayLen) {
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         final int dataSize = mType.mElement.getBytesSize() * count;
-        data1DChecks(off, count, arrayLen * dt.mSize, dataSize);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt);
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+                              mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1064,8 +1075,24 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
+        final int dataSize = mType.mElement.getBytesSize() * w * h;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
-                              array, arrayLen * dt.mSize, dt);
+                              array, sizeBytes, dt,
+                              mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1226,8 +1253,24 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFromUnchecked");
         mRS.validate();
         validate3DRange(xoff, yoff, zoff, w, h, d);
+        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
         mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
-                              array, arrayLen * dt.mSize, dt);
+                              array, sizeBytes, dt,
+                              mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1242,7 +1285,7 @@
      * @param w Width of the region to update
      * @param h Height of the region to update
      * @param d Depth of the region to update
-     * @param data to be placed into the allocation
+     * @param array to be placed into the allocation
      */
     public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFrom");
@@ -1300,7 +1343,11 @@
                 "Size of output array cannot be smaller than size of allocation.");
         }
         mRS.validate();
-        mRS.nAllocationRead(getID(mRS), array, dt);
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1367,35 +1414,8 @@
 
     /**
      * @hide
-     * Copy subelement from the Allocation into an object array.
-     * This is intended to be used with user defined structs
-     *
-     * @param xoff
-     * @param component_number
-     * @param array
-     */
-    public void copyElementTo(int xoff, int component_number, Object array) {
-        copyElementTo(xoff, 0, 0, component_number, array);
-    }
-
-    /**
-     * @hide
-     * Copy subelement from the Allocation into an object array.
-     * This is intended to be used with user defined structs
-     *
-     * @param xoff
-     * @param yoff
-     * @param component_number
-     * @param array
-     */
-    public void copyElementTo(int xoff, int yoff, int component_number, Object array) {
-        copyElementTo(xoff, yoff, 0, component_number, array);
-    }
-
-    /**
-     * @hide
-     * Copy subelement from the Allocation into an object array.
-     * This is intended to be used with user defined structs
+     * This is only intended to be used by auto-generated code reflected from
+     * the RenderScript script files and should not be used by developers.
      *
      * @param xoff
      * @param yoff
@@ -1403,8 +1423,7 @@
      * @param component_number
      * @param array
      */
-    public void copyElementTo(int xoff, int yoff, int zoff, int component_number, Object array) {
-        Trace.traceBegin(RenderScript.TRACE_TAG, "copyElementTo");
+    public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
         mRS.validate();
         if (component_number >= mType.mElement.mElements.length) {
             throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
@@ -1419,19 +1438,18 @@
             throw new RSIllegalArgumentException("Offset z must be >= 0.");
         }
 
-        Element.DataType dt = validateObjectIsPrimitiveArray(array, false);
-        int array_size = java.lang.reflect.Array.getLength(array) * dt.mSize;
+        final byte[] data = fp.getData();
+        int data_length = fp.getPos();
         int eSize = mType.mElement.mElements[component_number].getBytesSize();
         eSize *= mType.mElement.mArraySizes[component_number];
 
-        if (array_size < eSize) {
-            throw new RSIllegalArgumentException("Array Size (bytes)" + array_size +
-                                               " is smaller than component size " + eSize + ".");
+        if (data_length != eSize) {
+            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
+                                               " does not match component size " + eSize + ".");
         }
 
         mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                                   component_number, array, eSize, dt);
-        Trace.traceEnd(RenderScript.TRACE_TAG);
+                                   component_number, data, data_length);
     }
     /**
      * Resize a 1D allocation.  The contents of the allocation are preserved.
@@ -1469,8 +1487,14 @@
                                         Element.DataType dt, int arrayLen) {
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeToUnchecked");
         final int dataSize = mType.mElement.getBytesSize() * count;
-        data1DChecks(off, count, arrayLen * dt.mSize, dataSize);
-        mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt);
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+        mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+                              mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1624,8 +1648,23 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeToUnchecked");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
+        final int dataSize = mType.mElement.getBytesSize() * w * h;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
         mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
-                              array, arrayLen * dt.mSize, dt);
+                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1653,7 +1692,7 @@
      * @param yoff Y offset of the region to copy in this Allocation
      * @param w Width of the region to copy
      * @param h Height of the region to copy
-     * @param array Dest Array to be copied into
+     * @param data Dest Array to be copied into
      */
     public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
         validateIsInt8();
@@ -1669,7 +1708,7 @@
      * @param yoff Y offset of the region to copy in this Allocation
      * @param w Width of the region to copy
      * @param h Height of the region to copy
-     * @param array Dest Array to be copied into
+     * @param data Dest Array to be copied into
      */
     public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
         validateIsInt16();
@@ -1685,7 +1724,7 @@
      * @param yoff Y offset of the region to copy in this Allocation
      * @param w Width of the region to copy
      * @param h Height of the region to copy
-     * @param array Dest Array to be copied into
+     * @param data Dest Array to be copied into
      */
     public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
         validateIsInt32();
@@ -1701,7 +1740,7 @@
      * @param yoff Y offset of the region to copy in this Allocation
      * @param w Width of the region to copy
      * @param h Height of the region to copy
-     * @param array Dest Array to be copied into
+     * @param data Dest Array to be copied into
      */
     public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
         validateIsFloat32();
@@ -1719,8 +1758,23 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeToUnchecked");
         mRS.validate();
         validate3DRange(xoff, yoff, zoff, w, h, d);
+        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
         mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
-                              array, arrayLen * dt.mSize, dt);
+                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 1f3b63e..3d6d07f 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -484,10 +484,12 @@
     }
 
 
-    native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt);
-    synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt) {
+    native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
+        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
     native void rsnAllocationElementData(long con,long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes);
@@ -517,11 +519,13 @@
     }
 
     native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt);
+                                    int w, int h, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
     synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt) {
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
+        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
     native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, Bitmap b);
@@ -549,50 +553,56 @@
     }
 
     native void rsnAllocationData3D(long con, long id, int xoff, int yoff, int zoff, int mip,
-                                    int w, int h, int depth, Object d, int sizeBytes, int dt);
+                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
     synchronized void nAllocationData3D(long id, int xoff, int yoff, int zoff, int mip,
-                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) {
+                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID);
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes,
+                            dt.mID, mSize, usePadding);
     }
 
-    native void rsnAllocationRead(long con, long id, Object d, int dt);
-    synchronized void nAllocationRead(long id, Object d, Element.DataType dt) {
+    native void rsnAllocationRead(long con, long id, Object d, int dt, int mSize, boolean usePadding);
+    synchronized void nAllocationRead(long id, Object d, Element.DataType dt, int mSize, boolean usePadding) {
         validate();
-        rsnAllocationRead(mContext, id, d, dt.mID);
+        rsnAllocationRead(mContext, id, d, dt.mID, mSize, usePadding);
     }
 
     native void rsnAllocationRead1D(long con, long id, int off, int mip, int count, Object d,
-                                    int sizeBytes, int dt);
+                                    int sizeBytes, int dt, int mSize, boolean usePadding);
     synchronized void nAllocationRead1D(long id, int off, int mip, int count, Object d,
-                                        int sizeBytes, Element.DataType dt) {
+                                        int sizeBytes, Element.DataType dt, int mSize, boolean usePadding) {
         validate();
-        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
+        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
     native void rsnAllocationElementRead(long con,long id, int xoff, int yoff, int zoff,
-                                         int mip, int compIdx, Object d, int sizeBytes, int dt);
+                                         int mip, int compIdx, byte[] d, int sizeBytes);
     synchronized void nAllocationElementRead(long id, int xoff, int yoff, int zoff,
-                                             int mip, int compIdx, Object d, int sizeBytes,
-                                             Element.DataType dt) {
+                                             int mip, int compIdx, byte[] d, int sizeBytes) {
         validate();
-        rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes, dt.mID);
+        rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
     }
 
     native void rsnAllocationRead2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt);
+                                    int w, int h, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
     synchronized void nAllocationRead2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt) {
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
+        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
     native void rsnAllocationRead3D(long con, long id, int xoff, int yoff, int zoff, int mip,
-                                    int w, int h, int depth, Object d, int sizeBytes, int dt);
+                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
     synchronized void nAllocationRead3D(long id, int xoff, int yoff, int zoff, int mip,
-                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) {
+                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID);
+        rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
     native long  rsnAllocationGetType(long con, long id);
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index f1f0bfc..94f0859 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -14,7 +14,8 @@
     libskia \
     libutils \
     libui \
-    libgui
+    libgui \
+    libjnigraphics
 
 LOCAL_STATIC_LIBRARIES :=
 
@@ -23,6 +24,7 @@
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE) \
     frameworks/rs \
+    frameworks/base/core/jni \
     $(rs_generated_include_dir)
 
 LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index a145166..8483507 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -24,8 +24,6 @@
 #include <utils/misc.h>
 #include <inttypes.h>
 
-#include <SkBitmap.h>
-
 #include <androidfw/Asset.h>
 #include <androidfw/AssetManager.h>
 #include <androidfw/ResourceTypes.h>
@@ -35,6 +33,7 @@
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
 #include "android_runtime/android_util_AssetManager.h"
+#include "android/graphics/GraphicsJNI.h"
 
 #include <rs.h>
 #include <rsEnv.h>
@@ -54,10 +53,12 @@
 #define PER_ARRAY_TYPE(flag, fnc, readonly, ...) {                                      \
     jint len = 0;                                                                       \
     void *ptr = nullptr;                                                                \
+    void *srcPtr = nullptr;                                                             \
     size_t typeBytes = 0;                                                               \
     jint relFlag = 0;                                                                   \
     if (readonly) {                                                                     \
         /* The on-release mode should only be JNI_ABORT for read-only accesses. */      \
+        /* readonly = true, also indicates we are copying to the allocation   . */      \
         relFlag = JNI_ABORT;                                                            \
     }                                                                                   \
     switch(dataType) {                                                                  \
@@ -65,14 +66,50 @@
         len = _env->GetArrayLength((jfloatArray)data);                                  \
         ptr = _env->GetFloatArrayElements((jfloatArray)data, flag);                     \
         typeBytes = 4;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag);     \
         return;                                                                         \
     case RS_TYPE_FLOAT_64:                                                              \
         len = _env->GetArrayLength((jdoubleArray)data);                                 \
         ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag);                   \
         typeBytes = 8;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag);  \
         return;                                                                         \
     case RS_TYPE_SIGNED_8:                                                              \
@@ -80,7 +117,25 @@
         len = _env->GetArrayLength((jbyteArray)data);                                   \
         ptr = _env->GetByteArrayElements((jbyteArray)data, flag);                       \
         typeBytes = 1;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag);         \
         return;                                                                         \
     case RS_TYPE_SIGNED_16:                                                             \
@@ -88,7 +143,25 @@
         len = _env->GetArrayLength((jshortArray)data);                                  \
         ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
         typeBytes = 2;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag);     \
         return;                                                                         \
     case RS_TYPE_SIGNED_32:                                                             \
@@ -96,7 +169,25 @@
         len = _env->GetArrayLength((jintArray)data);                                    \
         ptr = _env->GetIntArrayElements((jintArray)data, flag);                         \
         typeBytes = 4;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag);           \
         return;                                                                         \
     case RS_TYPE_SIGNED_64:                                                             \
@@ -104,13 +195,31 @@
         len = _env->GetArrayLength((jlongArray)data);                                   \
         ptr = _env->GetLongArrayElements((jlongArray)data, flag);                       \
         typeBytes = 8;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag);        \
         return;                                                                         \
     default:                                                                            \
         break;                                                                          \
     }                                                                                   \
-    UNUSED(len, ptr, typeBytes, relFlag);                                               \
+    UNUSED(len, ptr, srcPtr, typeBytes, relFlag);                                       \
 }
 
 
@@ -172,18 +281,40 @@
 // ---------------------------------------------------------------------------
 
 static jfieldID gContextId = 0;
-static jfieldID gNativeBitmapID = 0;
 
 static void _nInit(JNIEnv *_env, jclass _this)
 {
     gContextId             = _env->GetFieldID(_this, "mContext", "J");
-
-    jclass bitmapClass = _env->FindClass("android/graphics/Bitmap");
-    gNativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
 }
 
 // ---------------------------------------------------------------------------
 
+static void copyWithPadding(void* ptr, void* srcPtr, int mSize, int count) {
+    int sizeBytesPad = mSize * 4;
+    int sizeBytes = mSize * 3;
+    uint8_t *dst = static_cast<uint8_t *>(ptr);
+    uint8_t *src = static_cast<uint8_t *>(srcPtr);
+    for (int i = 0; i < count; i++) {
+        memcpy(dst, src, sizeBytes);
+        dst += sizeBytesPad;
+        src += sizeBytes;
+    }
+}
+
+static void copyWithUnPadding(void* ptr, void* srcPtr, int mSize, int count) {
+    int sizeBytesPad = mSize * 4;
+    int sizeBytes = mSize * 3;
+    uint8_t *dst = static_cast<uint8_t *>(ptr);
+    uint8_t *src = static_cast<uint8_t *>(srcPtr);
+    for (int i = 0; i < count; i++) {
+        memcpy(dst, src, sizeBytes);
+        dst += sizeBytes;
+        src += sizeBytesPad;
+    }
+}
+
+
+// ---------------------------------------------------------------------------
 static void
 nContextFinish(JNIEnv *_env, jobject _this, jlong con)
 {
@@ -934,7 +1065,7 @@
                             jobject jbitmap, jint usage)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -951,7 +1082,7 @@
                                         jint mip, jobject jbitmap, jint usage)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -968,7 +1099,7 @@
                                 jobject jbitmap, jint usage)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -984,7 +1115,7 @@
 nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
     int w = bitmap.width();
     int h = bitmap.height();
@@ -1001,7 +1132,7 @@
 nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -1014,7 +1145,8 @@
 // Copies from the Java object data into the Allocation pointed to by _alloc.
 static void
 nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, jint sizeBytes, jint dataType)
+                  jint count, jobject data, jint sizeBytes, jint dataType, jint mSize,
+                  jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     if (kLogApi) {
@@ -1022,8 +1154,8 @@
               "dataType(%i)", (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes,
               dataType);
     }
-    PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count,
-                   ptr, sizeBytes);
+    PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true,
+                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
 }
 
 static void
@@ -1048,7 +1180,8 @@
 // Copies from the Java object data into the Allocation pointed to by _alloc.
 static void
 nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, jint sizeBytes, jint dataType)
+                  jint w, jint h, jobject data, jint sizeBytes, jint dataType, jint mSize,
+                  jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
@@ -1056,7 +1189,9 @@
         ALOGD("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
               "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
     }
-    PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+    int count = w * h;
+    PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true,
+                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
 }
 
 // Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -1090,7 +1225,8 @@
 // Copies from the Java object data into the Allocation pointed to by _alloc.
 static void
 nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                    jint w, jint h, jint d, jobject data, int sizeBytes, int dataType)
+                  jint w, jint h, jint d, jobject data, jint sizeBytes, jint dataType,
+                  jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     if (kLogApi) {
@@ -1098,7 +1234,9 @@
               " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
               lod, w, h, d, sizeBytes);
     }
-    PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+    int count = w * h * d;
+    PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true,
+                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
 }
 
 // Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -1130,47 +1268,57 @@
 
 // Copies from the Allocation pointed to by _alloc into the Java object data.
 static void
-nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, int dataType)
+nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, jint dataType,
+                jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     if (kLogApi) {
         ALOGD("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
     }
-    PER_ARRAY_TYPE(0, rsAllocationRead, false, (RsContext)con, alloc, ptr, len * typeBytes);
+    int count = 0;
+    PER_ARRAY_TYPE(0, rsAllocationRead, false,
+                   (RsContext)con, alloc, ptr, len * typeBytes);
 }
 
 // Copies from the Allocation pointed to by _alloc into the Java object data.
 static void
 nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, int sizeBytes, int dataType)
+                  jint count, jobject data, jint sizeBytes, jint dataType,
+                  jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     if (kLogApi) {
         ALOGD("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
               "dataType(%i)", (RsContext)con, alloc, offset, count, sizeBytes, dataType);
     }
-    PER_ARRAY_TYPE(0, rsAllocation1DRead, false, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+    PER_ARRAY_TYPE(0, rsAllocation1DRead, false,
+                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
 }
 
 // Copies from the Element in the Allocation pointed to by _alloc into the Java array data.
 static void
-nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc,
+nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
                        jint xoff, jint yoff, jint zoff,
-                       jint lod, jint compIdx, jobject data, jint sizeBytes, int dataType)
+                       jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
 {
-    RsAllocation *alloc = (RsAllocation *)_alloc;
+    jint len = _env->GetArrayLength(data);
     if (kLogApi) {
-        ALOGD("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), "
-              "sizeBytes(%i)", (RsContext)con, alloc, xoff, yoff, zoff, compIdx, sizeBytes);
+        ALOGD("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
+              "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
+              sizeBytes);
     }
-    PER_ARRAY_TYPE(0, rsAllocationElementRead, false, (RsContext)con, alloc,
-                   xoff, yoff, zoff, lod, ptr, sizeBytes, compIdx);
+    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    rsAllocationElementRead((RsContext)con, (RsAllocation)alloc,
+                            xoff, yoff, zoff,
+                            lod, ptr, sizeBytes, compIdx);    
+    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
 
 // Copies from the Allocation pointed to by _alloc into the Java object data.
 static void
 nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, int sizeBytes, int dataType)
+                  jint w, jint h, jobject data, jint sizeBytes, jint dataType,
+                  jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
@@ -1178,13 +1326,16 @@
         ALOGD("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
               "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
     }
-    PER_ARRAY_TYPE(0, rsAllocation2DRead, false, (RsContext)con, alloc, xoff, yoff, lod, face, w, h,
-                   ptr, sizeBytes, 0);
+    int count = w * h;
+    PER_ARRAY_TYPE(0, rsAllocation2DRead, false,
+                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
 }
+
 // Copies from the Allocation pointed to by _alloc into the Java object data.
 static void
 nAllocationRead3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                  jint w, jint h, jint d, jobject data, int sizeBytes, int dataType)
+                  jint w, jint h, jint d, jobject data, int sizeBytes, int dataType,
+                  jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     if (kLogApi) {
@@ -1192,8 +1343,9 @@
               " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
               lod, w, h, d, sizeBytes);
     }
-    PER_ARRAY_TYPE(0, rsAllocation3DRead, false, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d,
-                   ptr, sizeBytes, 0);
+    int count = w * h * d;
+    PER_ARRAY_TYPE(nullptr, rsAllocation3DRead, false,
+                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
 }
 
 static jlong
@@ -2214,17 +2366,17 @@
 {"rsnAllocationSetSurface",          "(JJLandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
 {"rsnAllocationIoSend",              "(JJ)V",                                 (void*)nAllocationIoSend },
 {"rsnAllocationIoReceive",           "(JJ)V",                                 (void*)nAllocationIoReceive },
-{"rsnAllocationData1D",              "(JJIIILjava/lang/Object;II)V",          (void*)nAllocationData1D },
+{"rsnAllocationData1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationData1D },
 {"rsnAllocationElementData",         "(JJIIIII[BI)V",                         (void*)nAllocationElementData },
-{"rsnAllocationData2D",              "(JJIIIIIILjava/lang/Object;II)V",       (void*)nAllocationData2D },
+{"rsnAllocationData2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationData2D },
 {"rsnAllocationData2D",              "(JJIIIIIIJIIII)V",                      (void*)nAllocationData2D_alloc },
-{"rsnAllocationData3D",              "(JJIIIIIIILjava/lang/Object;II)V",      (void*)nAllocationData3D },
+{"rsnAllocationData3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",    (void*)nAllocationData3D },
 {"rsnAllocationData3D",              "(JJIIIIIIIJIIII)V",                     (void*)nAllocationData3D_alloc },
-{"rsnAllocationRead",                "(JJLjava/lang/Object;I)V",              (void*)nAllocationRead },
-{"rsnAllocationRead1D",              "(JJIIILjava/lang/Object;II)V",          (void*)nAllocationRead1D },
-{"rsnAllocationElementRead",         "(JJIIIIILjava/lang/Object;II)V",        (void*)nAllocationElementRead },
-{"rsnAllocationRead2D",              "(JJIIIIIILjava/lang/Object;II)V",       (void*)nAllocationRead2D },
-{"rsnAllocationRead3D",              "(JJIIIIIIILjava/lang/Object;II)V",      (void*)nAllocationRead3D },
+{"rsnAllocationRead",                "(JJLjava/lang/Object;IIZ)V",            (void*)nAllocationRead },
+{"rsnAllocationRead1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationRead1D },
+{"rsnAllocationElementRead",         "(JJIIIII[BI)V",                         (void*)nAllocationElementRead },
+{"rsnAllocationRead2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationRead2D },
+{"rsnAllocationRead3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",    (void*)nAllocationRead3D },
 {"rsnAllocationGetType",             "(JJ)J",                                 (void*)nAllocationGetType},
 {"rsnAllocationResize1D",            "(JJI)V",                                (void*)nAllocationResize1D },
 {"rsnAllocationGenerateMipmaps",     "(JJ)V",                                 (void*)nAllocationGenerateMipmaps },
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 94d400a..26510328 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -601,7 +601,7 @@
         return token;
     }
 
-    // High level policy: apps are ineligible for backup if certain conditions apply
+    // High level policy: apps are generally ineligible for backup if certain conditions apply
     public static boolean appIsEligibleForBackup(ApplicationInfo app) {
         // 1. their manifest states android:allowBackup="false"
         if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
@@ -628,7 +628,7 @@
             return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
         }
 
-        // No agent means we do full backups for it
+        // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
         return true;
     }
 
@@ -1266,7 +1266,23 @@
                     for (int i = 0; i < N; i++) {
                         String pkgName = in.readUTF();
                         long lastBackup = in.readLong();
-                        schedule.add(new FullBackupEntry(pkgName, lastBackup));
+                        try {
+                            PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
+                            if (appGetsFullBackup(pkg)
+                                    && appIsEligibleForBackup(pkg.applicationInfo)) {
+                                schedule.add(new FullBackupEntry(pkgName, lastBackup));
+                            } else {
+                                if (DEBUG) {
+                                    Slog.i(TAG, "Package " + pkgName
+                                            + " no longer eligible for full backup");
+                                }
+                            }
+                        } catch (NameNotFoundException e) {
+                            if (DEBUG) {
+                                Slog.i(TAG, "Package " + pkgName
+                                        + " not installed; dropping from full backup");
+                            }
+                        }
                     }
                     Collections.sort(schedule);
                 } catch (Exception e) {
@@ -1289,7 +1305,7 @@
                 schedule = new ArrayList<FullBackupEntry>(N);
                 for (int i = 0; i < N; i++) {
                     PackageInfo info = apps.get(i);
-                    if (appGetsFullBackup(info)) {
+                    if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
                         schedule.add(new FullBackupEntry(info.packageName, 0));
                     }
                 }
@@ -1761,11 +1777,11 @@
                     addPackageParticipantsLocked(pkgList);
                 }
                 // If they're full-backup candidates, add them there instead
+                final long now = System.currentTimeMillis();
                 for (String packageName : pkgList) {
                     try {
                         PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
-                        long now = System.currentTimeMillis();
-                        if (appGetsFullBackup(app)) {
+                        if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob();
                         }
@@ -2462,7 +2478,7 @@
             BackupRequest request = mQueue.get(0);
             mQueue.remove(0);
 
-            Slog.d(TAG, "starting agent for backup of " + request);
+            Slog.d(TAG, "starting key/value backup of " + request);
             addBackupTrace("launch agent for " + request.packageName);
 
             // Verify that the requested app exists; it might be something that
@@ -2473,13 +2489,24 @@
             try {
                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
                         PackageManager.GET_SIGNATURES);
-                if (mCurrentPackage.applicationInfo.backupAgentName == null) {
+                if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
                     // The manifest has changed but we had a stale backup request pending.
                     // This won't happen again because the app won't be requesting further
                     // backups.
                     Slog.i(TAG, "Package " + request.packageName
                             + " no longer supports backup; skipping");
-                    addBackupTrace("skipping - no agent, completion is noop");
+                    addBackupTrace("skipping - not eligible, completion is noop");
+                    executeNextState(BackupState.RUNNING_QUEUE);
+                    return;
+                }
+
+                if (appGetsFullBackup(mCurrentPackage)) {
+                    // It's possible that this app *formerly* was enqueued for key/value backup,
+                    // but has since been updated and now only supports the full-data path.
+                    // Don't proceed with a key/value backup for it in this case.
+                    Slog.i(TAG, "Package " + request.packageName
+                            + " requests full-data rather than key/value; skipping");
+                    addBackupTrace("skipping - fullBackupOnly, completion is noop");
                     executeNextState(BackupState.RUNNING_QUEUE);
                     return;
                 }
@@ -9161,6 +9188,8 @@
             // check whether there is data for it in the current dataset, falling back
             // to the ancestral dataset if not.
             long token = getAvailableRestoreToken(packageName);
+            if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
+                    + " token=" + Long.toHexString(token));
 
             // If we didn't come up with a place to look -- no ancestral dataset and
             // the app has never been backed up from this device -- there's nothing
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index a2c87b9..e6dc1c7 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -291,7 +291,7 @@
                         }
                         canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
                         canvas.restore();
-                        atlasMap[mapIndex++] = bitmap.mNativeBitmap;
+                        atlasMap[mapIndex++] = bitmap.getSkBitmap();
                         atlasMap[mapIndex++] = entry.x;
                         atlasMap[mapIndex++] = entry.y;
                         atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index c03bb58..d81daa9 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -238,12 +238,21 @@
 
     public void writePatternHash(byte[] hash, int userId) {
         writeFile(getLockPatternFilename(userId), hash);
+        clearPasswordHash(userId);
+    }
+
+    private void clearPatternHash(int userId) {
+        writeFile(getLockPatternFilename(userId), null);
     }
 
     public void writePasswordHash(byte[] hash, int userId) {
         writeFile(getLockPasswordFilename(userId), hash);
+        clearPatternHash(userId);
     }
 
+    private void clearPasswordHash(int userId) {
+        writeFile(getLockPasswordFilename(userId), null);
+    }
 
     @VisibleForTesting
     String getLockPatternFilename(int userId) {
@@ -279,16 +288,15 @@
         return userId;
     }
 
-
     public void removeUser(int userId) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
 
         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
         final UserInfo parentInfo = um.getProfileParent(userId);
 
-        synchronized (mFileWriteLock) {
-            if (parentInfo == null) {
-                // This user owns its lock settings files - safe to delete them
+        if (parentInfo == null) {
+            // This user owns its lock settings files - safe to delete them
+            synchronized (mFileWriteLock) {
                 String name = getLockPasswordFilename(userId);
                 File file = new File(name);
                 if (file.exists()) {
diff --git a/services/core/java/com/android/server/MidiService.java b/services/core/java/com/android/server/MidiService.java
index 59b82da..7f98b30 100644
--- a/services/core/java/com/android/server/MidiService.java
+++ b/services/core/java/com/android/server/MidiService.java
@@ -17,10 +17,18 @@
 package com.android.server;
 
 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.content.pm.ServiceInfo;
+import android.content.res.XmlResourceParser;
+import android.media.midi.IMidiDeviceListener;
 import android.media.midi.IMidiDeviceServer;
-import android.media.midi.IMidiListener;
 import android.media.midi.IMidiManager;
 import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceService;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -28,12 +36,17 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 public class MidiService extends IMidiManager.Stub {
     private static final String TAG = "MidiService";
@@ -53,6 +66,27 @@
     // used for assigning IDs to MIDI devices
     private int mNextDeviceId = 1;
 
+    private final PackageManager mPackageManager;
+
+    // PackageMonitor for listening to package changes
+    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            addPackageDeviceServers(packageName);
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
+            removePackageDeviceServers(packageName);
+            addPackageDeviceServers(packageName);
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            removePackageDeviceServers(packageName);
+        }
+    };
+
     private final class Client implements IBinder.DeathRecipient {
         // Binder token for this client
         private final IBinder mToken;
@@ -61,7 +95,8 @@
         // This client's PID
         private final int mPid;
         // List of all receivers for this client
-        private final ArrayList<IMidiListener> mListeners = new ArrayList<IMidiListener>();
+        private final ArrayList<IMidiDeviceListener> mListeners
+                = new ArrayList<IMidiDeviceListener>();
 
         public Client(IBinder token) {
             mToken = token;
@@ -73,11 +108,11 @@
             return mUid;
         }
 
-        public void addListener(IMidiListener listener) {
+        public void addListener(IMidiDeviceListener listener) {
             mListeners.add(listener);
         }
 
-        public void removeListener(IMidiListener listener) {
+        public void removeListener(IMidiDeviceListener listener) {
             mListeners.remove(listener);
             if (mListeners.size() == 0) {
                 removeClient(mToken);
@@ -90,7 +125,7 @@
 
             MidiDeviceInfo deviceInfo = device.getDeviceInfo();
             try {
-                for (IMidiListener listener : mListeners) {
+                for (IMidiDeviceListener listener : mListeners) {
                     listener.onDeviceAdded(deviceInfo);
                 }
             } catch (RemoteException e) {
@@ -104,7 +139,7 @@
 
             MidiDeviceInfo deviceInfo = device.getDeviceInfo();
             try {
-                for (IMidiListener listener : mListeners) {
+                for (IMidiDeviceListener listener : mListeners) {
                     listener.onDeviceRemoved(deviceInfo);
                 }
             } catch (RemoteException e) {
@@ -152,16 +187,17 @@
     private final class Device implements IBinder.DeathRecipient {
         private final IMidiDeviceServer mServer;
         private final MidiDeviceInfo mDeviceInfo;
-        // UID of device creator
+        // ServiceInfo for the device's MidiDeviceServer implementation (virtual devices only)
+        private final ServiceInfo mServiceInfo;
+        // UID of device implementation
         private final int mUid;
-        // PID of device creator
-        private final int mPid;
 
-        public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo) {
+        public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo,
+                ServiceInfo serviceInfo, int uid) {
             mServer = server;
             mDeviceInfo = deviceInfo;
-            mUid = Binder.getCallingUid();
-            mPid = Binder.getCallingPid();
+            mServiceInfo = serviceInfo;
+            mUid = uid;
         }
 
         public MidiDeviceInfo getDeviceInfo() {
@@ -172,13 +208,20 @@
             return mServer;
         }
 
+        public ServiceInfo getServiceInfo() {
+            return mServiceInfo;
+        }
+
+        public String getPackageName() {
+            return (mServiceInfo == null ? null : mServiceInfo.packageName);
+        }
+
         public boolean isUidAllowed(int uid) {
-            // FIXME
-            return true;
+            return (!mDeviceInfo.isPrivate() || mUid == uid);
         }
 
         public void binderDied() {
-            synchronized (mDevicesByServer) {
+            synchronized (mDevicesByInfo) {
                 removeDeviceLocked(this);
             }
         }
@@ -189,32 +232,59 @@
             sb.append(mDeviceInfo);
             sb.append(" UID: ");
             sb.append(mUid);
-            sb.append(" PID: ");
-            sb.append(mPid);
             return sb.toString();
         }
     }
 
     public MidiService(Context context) {
         mContext = context;
-    }
+        mPackageManager = context.getPackageManager();
+        mPackageMonitor.register(context, null, true);
 
-    public void registerListener(IBinder token, IMidiListener listener) {
+        Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
+        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(intent,
+                PackageManager.GET_META_DATA);
+        if (resolveInfos != null) {
+            int count = resolveInfos.size();
+            for (int i = 0; i < count; i++) {
+                ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+                if (serviceInfo != null) {
+                    addPackageDeviceServer(serviceInfo);
+                }
+            }
+        }
+   }
+
+    @Override
+    public void registerListener(IBinder token, IMidiDeviceListener listener) {
         Client client = getClient(token);
         if (client == null) return;
         client.addListener(listener);
     }
 
-    public void unregisterListener(IBinder token, IMidiListener listener) {
+    @Override
+    public void unregisterListener(IBinder token, IMidiDeviceListener listener) {
         Client client = getClient(token);
         if (client == null) return;
         client.removeListener(listener);
     }
 
     public MidiDeviceInfo[] getDeviceList() {
-        return mDevicesByInfo.keySet().toArray(new MidiDeviceInfo[0]);
+        ArrayList<MidiDeviceInfo> deviceInfos = new ArrayList<MidiDeviceInfo>();
+        int uid = Binder.getCallingUid();
+
+        synchronized (mDevicesByInfo) {
+            for (Device device : mDevicesByInfo.values()) {
+                if (device.isUidAllowed(uid)) {
+                    deviceInfos.add(device.getDeviceInfo());
+                }
+            }
+        }
+
+        return deviceInfos.toArray(new MidiDeviceInfo[0]);
     }
 
+    @Override
     public IMidiDeviceServer openDevice(IBinder token, MidiDeviceInfo deviceInfo) {
         Device device = mDevicesByInfo.get(deviceInfo);
         if (device == null) {
@@ -229,28 +299,64 @@
         return device.getDeviceServer();
     }
 
+    @Override
     public MidiDeviceInfo registerDeviceServer(IMidiDeviceServer server, int numInputPorts,
-            int numOutputPorts, Bundle properties, boolean isPrivate, int type) {
+            int numOutputPorts, Bundle properties, int type) {
         if (type != MidiDeviceInfo.TYPE_VIRTUAL && Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("only system can create non-virtual devices");
         }
 
-        MidiDeviceInfo deviceInfo;
-        Device device;
+        synchronized (mDevicesByInfo) {
+            return addDeviceLocked(type, numInputPorts, numOutputPorts, properties,
+            server, null, false, -1);
+        }
+    }
 
-        synchronized (mDevicesByServer) {
-            int id = mNextDeviceId++;
-            deviceInfo = new MidiDeviceInfo(type, id, numInputPorts, numOutputPorts, properties);
+    @Override
+    public void unregisterDeviceServer(IMidiDeviceServer server) {
+        synchronized (mDevicesByInfo) {
+            Device device = mDevicesByServer.get(server.asBinder());
+            if (device != null) {
+                removeDeviceLocked(device);
+            }
+        }
+    }
+
+    @Override
+    public MidiDeviceInfo getServiceDeviceInfo(String packageName, String className) {
+        synchronized (mDevicesByInfo) {
+            for (Device device : mDevicesByInfo.values()) {
+                 ServiceInfo serviceInfo = device.getServiceInfo();
+                 if (serviceInfo != null &&
+                        packageName.equals(serviceInfo.packageName) &&
+                        className.equals(serviceInfo.name)) {
+                    return device.getDeviceInfo();
+                }
+            }
+            return null;
+        }
+    }
+
+    // synchronize on mDevicesByInfo
+    private MidiDeviceInfo addDeviceLocked(int type, int numInputPorts, int numOutputPorts,
+            Bundle properties, IMidiDeviceServer server, ServiceInfo serviceInfo,
+            boolean isPrivate, int uid) {
+
+        int id = mNextDeviceId++;
+        MidiDeviceInfo deviceInfo = new MidiDeviceInfo(type, id, numInputPorts, numOutputPorts,
+                properties, isPrivate);
+        Device device = new Device(server, deviceInfo, serviceInfo, uid);
+
+        if (server != null) {
             IBinder binder = server.asBinder();
-            device = new Device(server, deviceInfo);
             try {
                 binder.linkToDeath(device, 0);
             } catch (RemoteException e) {
                 return null;
             }
-            mDevicesByInfo.put(deviceInfo, device);
-            mDevicesByServer.put(server.asBinder(), device);
+            mDevicesByServer.put(binder, device);
         }
+        mDevicesByInfo.put(deviceInfo, device);
 
         synchronized (mClients) {
             for (Client c : mClients.values()) {
@@ -261,16 +367,13 @@
         return deviceInfo;
     }
 
-    public void unregisterDeviceServer(IMidiDeviceServer server) {
-        synchronized (mDevicesByServer) {
-            removeDeviceLocked(mDevicesByServer.get(server.asBinder()));
-        }
-    }
-
-    // synchronize on mDevicesByServer
+    // synchronize on mDevicesByInfo
     private void removeDeviceLocked(Device device) {
-        if (mDevicesByServer.remove(device.getDeviceServer().asBinder()) != null) {
-            mDevicesByInfo.remove(device.getDeviceInfo());
+        if (mDevicesByInfo.remove(device.getDeviceInfo()) != null) {
+            IMidiDeviceServer server = device.getDeviceServer();
+            if (server != null) {
+                mDevicesByServer.remove(server);
+            }
 
             synchronized (mClients) {
                 for (Client c : mClients.values()) {
@@ -280,6 +383,134 @@
         }
     }
 
+    private void addPackageDeviceServers(String packageName) {
+        PackageInfo info;
+
+        try {
+            info = mPackageManager.getPackageInfo(packageName,
+                    PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+            return;
+        }
+
+        ServiceInfo[] services = info.services;
+        if (services == null) return;
+        for (int i = 0; i < services.length; i++) {
+            addPackageDeviceServer(services[i]);
+        }
+    }
+
+    private void addPackageDeviceServer(ServiceInfo serviceInfo) {
+        XmlResourceParser parser = null;
+
+        try {
+            parser = serviceInfo.loadXmlMetaData(mPackageManager,
+                    MidiDeviceService.SERVICE_INTERFACE);
+            if (parser == null) return;
+
+            Bundle properties = null;
+            int numInputPorts = 0;
+            int numOutputPorts = 0;
+            boolean isPrivate = false;
+
+            while (true) {
+                int eventType = parser.next();
+                if (eventType == XmlPullParser.END_DOCUMENT) {
+                    break;
+                } else if (eventType == XmlPullParser.START_TAG) {
+                    String tagName = parser.getName();
+                    if ("device".equals(tagName)) {
+                        if (properties != null) {
+                            Log.w(TAG, "nested <device> elements in metadata for "
+                                + serviceInfo.packageName);
+                            continue;
+                        }
+                        properties = new Bundle();
+                        properties.putParcelable(MidiDeviceInfo.PROPERTY_SERVICE_INFO, serviceInfo);
+                        numInputPorts = 0;
+                        numOutputPorts = 0;
+                        isPrivate = false;
+
+                        int count = parser.getAttributeCount();
+                        for (int i = 0; i < count; i++) {
+                            String name = parser.getAttributeName(i);
+                            String value = parser.getAttributeValue(i);
+                            if ("private".equals(name)) {
+                                isPrivate = "true".equals(value);
+                            } else {
+                                properties.putString(name, value);
+                            }
+                        }
+                    } else if ("input-port".equals(tagName)) {
+                        if (properties == null) {
+                            Log.w(TAG, "<input-port> outside of <device> in metadata for "
+                                + serviceInfo.packageName);
+                            continue;
+                        }
+                        numInputPorts++;
+                        // TODO - add support for port properties
+                    } else if ("output-port".equals(tagName)) {
+                        if (properties == null) {
+                            Log.w(TAG, "<output-port> outside of <device> in metadata for "
+                                + serviceInfo.packageName);
+                            continue;
+                        }
+                        numOutputPorts++;
+                        // TODO - add support for port properties
+                    }
+                } else if (eventType == XmlPullParser.END_TAG) {
+                    String tagName = parser.getName();
+                    if ("device".equals(tagName)) {
+                        if (properties != null) {
+                            if (numInputPorts == 0 && numOutputPorts == 0) {
+                                Log.w(TAG, "<device> with no ports in metadata for "
+                                    + serviceInfo.packageName);
+                                continue;
+                            }
+
+                            int uid = -1;
+                            if (isPrivate) {
+                                try {
+                                    ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+                                            serviceInfo.packageName, 0);
+                                    uid = appInfo.uid;
+                                } catch (PackageManager.NameNotFoundException e) {
+                                    Log.e(TAG, "could not fetch ApplicationInfo for "
+                                            + serviceInfo.packageName);
+                                    continue;
+                                }
+                            }
+
+                            synchronized (mDevicesByInfo) {
+                                addDeviceLocked(MidiDeviceInfo.TYPE_VIRTUAL,
+                                    numInputPorts, numOutputPorts, properties,
+                                    null, serviceInfo, isPrivate, uid);
+                            }
+                            // setting properties to null signals that we are no longer
+                            // processing a <device>
+                            properties = null;
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Unable to load component info " + serviceInfo.toString(), e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    private void removePackageDeviceServers(String packageName) {
+        synchronized (mDevicesByInfo) {
+            for (Device device : mDevicesByInfo.values()) {
+                if (packageName.equals(device.getPackageName())) {
+                    removeDeviceLocked(device);
+                }
+            }
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 059dde1..fc95b00 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -33,6 +35,7 @@
 import android.os.SystemProperties;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
@@ -67,14 +70,15 @@
 import android.util.TimeUtils;
 
 public final class ActiveServices {
-    static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
-    static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
-    static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
-    static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
-    static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
-    static final boolean LOG_SERVICE_START_STOP = false;
-    static final String TAG = ActivityManagerService.TAG;
-    static final String TAG_MU = ActivityManagerService.TAG_MU;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
+    private static final String TAG_MU = TAG + POSTFIX_MU;
+    private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
+    private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING;
+
+    private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE;
+    private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
+
+    private static final boolean LOG_SERVICE_START_STOP = false;
 
     // How long we wait for a service to finish executing.
     static final int SERVICE_TIMEOUT = 20*1000;
@@ -206,11 +210,12 @@
 
         void ensureNotStartingBackground(ServiceRecord r) {
             if (mStartingBackground.remove(r)) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer background starting: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "No longer background starting: " + r);
                 rescheduleDelayedStarts();
             }
             if (mDelayedStartList.remove(r)) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer delaying start: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
             }
         }
 
@@ -229,16 +234,17 @@
             while (mDelayedStartList.size() > 0
                     && mStartingBackground.size() < mMaxStartingBackground) {
                 ServiceRecord r = mDelayedStartList.remove(0);
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "REM FR DELAY LIST (exec next): " + r);
                 if (r.pendingStarts.size() <= 0) {
                     Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
                             + " delayedStop=" + r.delayedStop);
                 }
                 if (DEBUG_DELAYED_SERVICE) {
                     if (mDelayedStartList.size() > 0) {
-                        Slog.v(TAG, "Remaining delayed list:");
+                        Slog.v(TAG_SERVICE, "Remaining delayed list:");
                         for (int i=0; i<mDelayedStartList.size(); i++) {
-                            Slog.v(TAG, "  #" + i + ": " + mDelayedStartList.get(i));
+                            Slog.v(TAG_SERVICE, "  #" + i + ": " + mDelayedStartList.get(i));
                         }
                     }
                 }
@@ -248,7 +254,7 @@
             if (mStartingBackground.size() > 0) {
                 ServiceRecord next = mStartingBackground.get(0);
                 long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
-                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Top bg start is " + next
+                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Top bg start is " + next
                         + ", can delay others up to " + when);
                 Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
                 sendMessageAtTime(msg, when);
@@ -298,7 +304,7 @@
     ComponentName startServiceLocked(IApplicationThread caller,
             Intent service, String resolvedType,
             int callingPid, int callingUid, int userId) {
-        if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "startService: " + service
+        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
                 + " type=" + resolvedType + " args=" + service.getExtras());
 
         final boolean callerFg;
@@ -337,7 +343,7 @@
         NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                 callingUid, r.packageName, service, service.getFlags(), null, r.userId);
         if (unscheduleServiceRestartLocked(r, callingUid, false)) {
-            if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
         }
         r.lastActivity = SystemClock.uptimeMillis();
         r.startRequested = true;
@@ -360,29 +366,30 @@
                 // service is started.  This is especially the case for receivers, which
                 // may start a service in onReceive() to do some additional work and have
                 // initialized some global state as part of that.
-                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in "
-                        + proc);
+                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+                        + r + " in " + proc);
                 if (r.delayed) {
                     // This service is already scheduled for a delayed start; just leave
                     // it still waiting.
-                    if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Continuing to delay: " + r);
+                    if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
                     return r.name;
                 }
                 if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                     // Something else is starting, delay!
-                    Slog.i(TAG, "Delaying start of: " + r);
+                    Slog.i(TAG_SERVICE, "Delaying start of: " + r);
                     smap.mDelayedStartList.add(r);
                     r.delayed = true;
                     return r.name;
                 }
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
                 addToStarting = true;
             } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
                 // We slightly loosen when we will enqueue this new service as a background
                 // starting service we are waiting for, to also include processes that are
                 // currently running other services or receivers.
                 addToStarting = true;
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "Not delaying, but counting as bg: " + r);
             } else if (DEBUG_DELAYED_STARTS) {
                 StringBuilder sb = new StringBuilder(128);
                 sb.append("Not potential delay (state=").append(proc.curProcState)
@@ -394,16 +401,17 @@
                 }
                 sb.append("): ");
                 sb.append(r.toString());
-                Slog.v(TAG, sb.toString());
+                Slog.v(TAG_SERVICE, sb.toString());
             }
         } else if (DEBUG_DELAYED_STARTS) {
             if (callerFg) {
-                Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+                Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
                         + callingUid + " pid=" + callingPid + "): " + r);
             } else if (r.app != null) {
-                Slog.v(TAG, "Not potential delay (cur app=" + r.app + "): " + r);
+                Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
             } else {
-                Slog.v(TAG, "Not potential delay (user " + r.userId + " not started): " + r);
+                Slog.v(TAG_SERVICE,
+                        "Not potential delay (user " + r.userId + " not started): " + r);
             }
         }
 
@@ -432,9 +440,9 @@
             if (DEBUG_DELAYED_SERVICE) {
                 RuntimeException here = new RuntimeException("here");
                 here.fillInStackTrace();
-                Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
+                Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
             } else if (DEBUG_DELAYED_STARTS) {
-                Slog.v(TAG, "Starting background (first=" + first + "): " + r);
+                Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
             }
             if (first) {
                 smap.rescheduleDelayedStarts();
@@ -451,7 +459,7 @@
             // If service isn't actually running, but is is being held in the
             // delayed list, then we need to keep it started but note that it
             // should be stopped once no longer delayed.
-            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Delaying stop of pending: " + service);
+            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
             service.delayedStop = true;
             return;
         }
@@ -469,7 +477,7 @@
 
     int stopServiceLocked(IApplicationThread caller, Intent service,
             String resolvedType, int userId) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopService: " + service
                 + " type=" + resolvedType);
 
         final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -525,7 +533,7 @@
 
     boolean stopServiceTokenLocked(ComponentName className, IBinder token,
             int startId) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "stopServiceToken: " + className
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className
                 + " " + token + " startId=" + startId);
         ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
         if (r != null) {
@@ -687,7 +695,7 @@
     int bindServiceLocked(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType,
             IServiceConnection connection, int flags, int userId) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
                 + " type=" + resolvedType + " conn=" + connection.asBinder()
                 + " flags=0x" + Integer.toHexString(flags));
         final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -751,7 +759,7 @@
 
         try {
             if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
-                if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: "
                         + s);
             }
 
@@ -819,7 +827,7 @@
                 mAm.updateOomAdjLocked(s.app);
             }
 
-            if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
                     + ": received=" + b.intent.received
                     + " apps=" + b.intent.apps.size()
                     + " doRebind=" + b.intent.doRebind);
@@ -857,7 +865,7 @@
     void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
         final long origId = Binder.clearCallingIdentity();
         try {
-            if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                     + " " + intent + ": " + service);
             if (r != null) {
                 Intent.FilterComparison filter
@@ -873,14 +881,14 @@
                             ConnectionRecord c = clist.get(i);
                             if (!filter.equals(c.binding.intent.intent)) {
                                 if (DEBUG_SERVICE) Slog.v(
-                                        TAG, "Not publishing to: " + c);
+                                        TAG_SERVICE, "Not publishing to: " + c);
                                 if (DEBUG_SERVICE) Slog.v(
-                                        TAG, "Bound intent: " + c.binding.intent.intent);
+                                        TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                                 if (DEBUG_SERVICE) Slog.v(
-                                        TAG, "Published intent: " + intent);
+                                        TAG_SERVICE, "Published intent: " + intent);
                                 continue;
                             }
-                            if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
+                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                             try {
                                 c.conn.connected(r.name, service);
                             } catch (Exception e) {
@@ -901,7 +909,7 @@
 
     boolean unbindServiceLocked(IServiceConnection connection) {
         IBinder binder = connection.asBinder();
-        if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
         ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
         if (clist == null) {
             Slog.w(TAG, "Unbind failed: could not find connection for "
@@ -945,7 +953,7 @@
                 Intent.FilterComparison filter
                         = new Intent.FilterComparison(intent);
                 IntentBindRecord b = r.bindings.get(filter);
-                if (DEBUG_SERVICE) Slog.v(TAG, "unbindFinished in " + r
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindFinished in " + r
                         + " at " + b + ": apps="
                         + (b != null ? b.apps.size() : 0));
 
@@ -1012,7 +1020,7 @@
             String resolvedType, int callingPid, int callingUid, int userId,
             boolean createIfNeeded, boolean callingFromFg) {
         ServiceRecord r = null;
-        if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
                 + " type=" + resolvedType + " callingUid=" + callingUid);
 
         userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
@@ -1036,7 +1044,7 @@
                 ServiceInfo sInfo =
                     rInfo != null ? rInfo.serviceInfo : null;
                 if (sInfo == null) {
-                    Slog.w(TAG, "Unable to start service " + service + " U=" + userId +
+                    Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
                           ": not found");
                     return null;
                 }
@@ -1110,9 +1118,9 @@
     }
 
     private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
-        if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING "
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
                 + why + " of " + r + " in app " + r.app);
-        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, ">>> EXECUTING "
+        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
                 + why + " of " + r.shortName);
         long now = SystemClock.uptimeMillis();
         if (r.executeNesting == 0) {
@@ -1155,7 +1163,7 @@
                 i.hasBound = true;
                 i.doRebind = false;
             } catch (RemoteException e) {
-                if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                 return false;
             }
         }
@@ -1336,7 +1344,7 @@
             return null;
         }
 
-        if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);
 
         // We are now bringing the service up, so no longer in the
         // restarting state.
@@ -1347,7 +1355,7 @@
 
         // Make sure this service is no longer considered delayed, we are starting it now.
         if (r.delayed) {
-            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
+            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
             getServiceMap(r.userId).mDelayedStartList.remove(r);
             r.delayed = false;
         }
@@ -1430,7 +1438,8 @@
             // Oh and hey we've already been asked to stop!
             r.delayedStop = false;
             if (r.startRequested) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "Applying delayed stop (in bring up): " + r);
                 stopServiceLocked(r);
             }
         }
@@ -1509,7 +1518,7 @@
         sendServiceArgsLocked(r, execInFg, true);
 
         if (r.delayed) {
-            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
+            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
             getServiceMap(r.userId).mDelayedStartList.remove(r);
             r.delayed = false;
         }
@@ -1518,7 +1527,8 @@
             // Oh and hey we've already been asked to stop!
             r.delayedStop = false;
             if (r.startRequested) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "Applying delayed stop (from start): " + r);
                 stopServiceLocked(r);
             }
         }
@@ -1534,7 +1544,7 @@
         while (r.pendingStarts.size() > 0) {
             try {
                 ServiceRecord.StartItem si = r.pendingStarts.remove(0);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: "
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Sending arguments to: "
                         + r + " " + r.intent + " args=" + si.intent);
                 if (si.intent == null && N > 1) {
                     // If somehow we got a dummy null intent in the middle,
@@ -1566,7 +1576,7 @@
             } catch (RemoteException e) {
                 // Remote process gone...  we'll let the normal cleanup take
                 // care of this.
-                if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while scheduling start: " + r);
                 break;
             } catch (Exception e) {
                 Slog.w(TAG, "Unexpected exception", e);
@@ -1636,7 +1646,7 @@
         if (r.app != null && r.app.thread != null) {
             for (int i=r.bindings.size()-1; i>=0; i--) {
                 IntentBindRecord ibr = r.bindings.valueAt(i);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr
                         + ": hasBound=" + ibr.hasBound);
                 if (ibr.hasBound) {
                     try {
@@ -1654,7 +1664,7 @@
             }
         }
 
-        if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down " + r + " " + r.intent);
         r.destroyTime = SystemClock.uptimeMillis();
         if (LOG_SERVICE_START_STOP) {
             EventLogTags.writeAmDestroyService(
@@ -1671,7 +1681,7 @@
         for (int i=mPendingServices.size()-1; i>=0; i--) {
             if (mPendingServices.get(i) == r) {
                 mPendingServices.remove(i);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Removed pending: " + r);
             }
         }
 
@@ -1704,11 +1714,11 @@
                 }
             } else {
                 if (DEBUG_SERVICE) Slog.v(
-                    TAG, "Removed service that has no process: " + r);
+                    TAG_SERVICE, "Removed service that has no process: " + r);
             }
         } else {
             if (DEBUG_SERVICE) Slog.v(
-                TAG, "Removed service that is not running: " + r);
+                TAG_SERVICE, "Removed service that is not running: " + r);
         }
 
         if (r.bindings.size() > 0) {
@@ -1775,7 +1785,7 @@
         }
 
         if (!c.serviceDead) {
-            if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
                     + ": shouldUnbind=" + b.intent.hasBound);
             if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                     && b.intent.hasBound) {
@@ -1902,19 +1912,20 @@
 
     private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
             boolean finishing) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r
                 + ": nesting=" + r.executeNesting
                 + ", inDestroying=" + inDestroying + ", app=" + r.app);
-        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
+        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
+                "<<< DONE EXECUTING " + r.shortName);
         r.executeNesting--;
         if (r.executeNesting <= 0) {
             if (r.app != null) {
-                if (DEBUG_SERVICE) Slog.v(TAG,
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                         "Nesting at 0 of " + r.shortName);
                 r.app.execServicesFg = false;
                 r.app.executingServices.remove(r);
                 if (r.app.executingServices.size() == 0) {
-                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
+                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                             "No more executingServices of " + r.shortName);
                     mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                 } else if (r.executeFg) {
@@ -1927,7 +1938,7 @@
                     }
                 }
                 if (inDestroying) {
-                    if (DEBUG_SERVICE) Slog.v(TAG,
+                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                             "doneExecuting remove destroying " + r);
                     mDestroyingServices.remove(r);
                     r.bindings.clear();
@@ -2141,13 +2152,13 @@
             sr.executeNesting = 0;
             sr.forceClearTracker();
             if (mDestroyingServices.remove(sr)) {
-                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
             }
 
             final int numClients = sr.bindings.size();
             for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
                 IntentBindRecord b = sr.bindings.valueAt(bindingi);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Killing binding " + b
                         + ": shouldUnbind=" + b.hasBound);
                 b.binder = null;
                 b.requested = b.received = b.hasBound = false;
@@ -2281,7 +2292,7 @@
             if (sr.app == app) {
                 sr.forceClearTracker();
                 mDestroyingServices.remove(i);
-                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
new file mode 100644
index 0000000..03f253b
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -0,0 +1,84 @@
+/*
+ * 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.server.am;
+
+/**
+ * Common class for the various debug {@link android.util.Log} output configuration in the activity
+ * manager package.
+ */
+class ActivityManagerDebugConfig {
+
+    // All output logs in the activity manager package use the {@link #TAG_AM} string for tagging
+    // their log output. This makes it easy to identify the origin of the log message when sifting
+    // through a large amount of log output from multiple sources. However, it also makes trying
+    // to figure-out the origin of a log message while debugging the activity manager a little
+    // painful. By setting this constant to true, log messages from the activity manager package
+    // will be tagged with their class names instead fot the generic tag.
+    static final boolean TAG_WITH_CLASS_NAME = false;
+
+    // While debugging it is sometimes useful to have the category name of the log prepended to the
+    // base log tag to make sifting through logs with the same base tag easier. By setting this
+    // constant to true, the category name of the log point will be prepended to the log tag.
+    static final boolean PREPEND_CATEGORY_NAME = false;
+
+    // Default log tag for the activity manager package.
+    static final String TAG_AM = "ActivityManager";
+
+    // Enable all debug log categories.
+    static final boolean DEBUG_ALL = false;
+
+    // Available log categories in the activity manager package.
+    static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
+    static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
+    static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_CLEANUP = DEBUG_ALL || false;
+    static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
+    static final boolean DEBUG_FOCUS = false;
+    static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
+    static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
+    static final boolean DEBUG_LRU = DEBUG_ALL || false;
+    static final boolean DEBUG_MU = DEBUG_ALL || false;
+    static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
+    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+    static final boolean DEBUG_POWER = DEBUG_ALL || false;
+    static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
+    static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
+    static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
+    static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
+    static final boolean DEBUG_PSS = DEBUG_ALL || false;
+    static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
+    static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
+    static final boolean DEBUG_STACK = DEBUG_ALL || false;
+    static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
+    static final boolean DEBUG_TASKS = DEBUG_ALL || false;
+    static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
+    static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+    static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
+    static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
+    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+
+    static final String POSTFIX_BACKUP = (PREPEND_CATEGORY_NAME) ? "_Backup" : "";
+    static final String POSTFIX_BROADCAST = (PREPEND_CATEGORY_NAME) ? "_Broadcast" : "";
+    static final String POSTFIX_MU = "_MU";
+    static final String POSTFIX_SERVICE = (PREPEND_CATEGORY_NAME) ? "_Service" : "";
+    static final String POSTFIX_SERVICE_EXECUTING =
+            (PREPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 008d718..b9bb8d0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -30,6 +30,7 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 
 import android.Manifest;
@@ -55,11 +56,13 @@
 import android.service.voice.IVoiceInteractionSession;
 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;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.DumpHeapActivity;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
@@ -245,10 +248,11 @@
     // File that stores last updated system version and called preboot receivers
     static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
 
-    static final String TAG = "ActivityManager";
-    static final String TAG_MU = "ActivityManagerServiceMU";
-    static final boolean DEBUG = false;
-    static final boolean localLOGV = DEBUG;
+    static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
+    private static final String TAG_MU = TAG + POSTFIX_MU;
+
+    // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
+    static final boolean localLOGV = DEBUG_ALL || false;
     static final boolean DEBUG_BACKUP = localLOGV || false;
     static final boolean DEBUG_BROADCAST = localLOGV || false;
     static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
@@ -1124,6 +1128,11 @@
     boolean mAutoStopProfiler = false;
     int mProfileType = 0;
     String mOpenGlTraceApp = null;
+    final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>();
+    String mMemWatchDumpProcName;
+    String mMemWatchDumpFile;
+    int mMemWatchDumpPid;
+    int mMemWatchDumpUid;
 
     final long[] mTmpLong = new long[1];
 
@@ -1266,6 +1275,8 @@
     static final int DISMISS_DIALOG_MSG = 48;
     static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49;
     static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50;
+    static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;
+    static final int DELETE_DUMPHEAP_MSG = 52;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1820,6 +1831,78 @@
                 }
                 break;
             }
+            case POST_DUMP_HEAP_NOTIFICATION_MSG: {
+                final String procName;
+                final int uid;
+                final long memLimit;
+                synchronized (ActivityManagerService.this) {
+                    procName = mMemWatchDumpProcName;
+                    uid = mMemWatchDumpUid;
+                    Long limit = mMemWatchProcesses.get(procName);
+                    memLimit = limit != null ? limit : 0;
+                }
+                if (procName == null) {
+                    return;
+                }
+
+                if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from "
+                        + procName + "/" + uid);
+
+                INotificationManager inm = NotificationManager.getService();
+                if (inm == null) {
+                    return;
+                }
+
+                String text = mContext.getString(R.string.dump_heap_notification, procName);
+                Notification notification = new Notification();
+                notification.icon = com.android.internal.R.drawable.stat_sys_adb;
+                notification.when = 0;
+                notification.flags = Notification.FLAG_ONGOING_EVENT|Notification.FLAG_AUTO_CANCEL;
+                notification.tickerText = text;
+                notification.defaults = 0; // please be quiet
+                notification.sound = null;
+                notification.vibrate = null;
+                notification.color = mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color);
+                Intent deleteIntent = new Intent();
+                deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+                notification.deleteIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
+                        deleteIntent, 0, UserHandle.OWNER);
+                Intent intent = new Intent();
+                intent.setClassName("android", DumpHeapActivity.class.getName());
+                intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
+                intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
+                int userId = UserHandle.getUserId(uid);
+                notification.setLatestEventInfo(mContext, text,
+                        mContext.getText(R.string.dump_heap_notification_detail),
+                        PendingIntent.getActivityAsUser(mContext, 0, intent,
+                                PendingIntent.FLAG_CANCEL_CURRENT, null,
+                                new UserHandle(userId)));
+
+                try {
+                    int[] outId = new int[1];
+                    inm.enqueueNotificationWithTag("android", "android", null,
+                            R.string.dump_heap_notification,
+                            notification, outId, userId);
+                } catch (RuntimeException e) {
+                    Slog.w(ActivityManagerService.TAG,
+                            "Error showing notification for dump heap", e);
+                } catch (RemoteException e) {
+                }
+            } break;
+            case DELETE_DUMPHEAP_MSG: {
+                revokeUriPermission(ActivityThread.currentActivityThread().getApplicationThread(),
+                        DumpHeapActivity.JAVA_URI,
+                        Intent.FLAG_GRANT_READ_URI_PERMISSION
+                                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                        UserHandle.myUserId());
+                synchronized (ActivityManagerService.this) {
+                    mMemWatchDumpFile = null;
+                    mMemWatchDumpProcName = null;
+                    mMemWatchDumpPid = -1;
+                    mMemWatchDumpUid = -1;
+                }
+            } break;
             }
         }
     };
@@ -1906,7 +1989,7 @@
                             if (pss != 0 && proc.thread != null && proc.setProcState == procState
                                     && proc.pid == pid && proc.lastPssTime == lastPssTime) {
                                 num++;
-                                recordPssSample(proc, procState, pss, tmp[0],
+                                recordPssSampleLocked(proc, procState, pss, tmp[0],
                                         SystemClock.uptimeMillis());
                             }
                         }
@@ -2318,7 +2401,7 @@
                                     }
                                     ps.addCpuTimeLocked(st.rel_utime - otherUTime,
                                             st.rel_stime - otherSTime, cpuSpeedTimes);
-                                    pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
+                                    pr.curCpuTime += st.rel_utime + st.rel_stime;
                                 } else {
                                     BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
                                     if (ps == null || !ps.isActive()) {
@@ -5704,7 +5787,7 @@
                     for (String pkg : pkgs) {
                         synchronized (ActivityManagerService.this) {
                             if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
-                                    0, "finished booting")) {
+                                    0, "query restart")) {
                                 setResultCode(Activity.RESULT_OK);
                                 return;
                             }
@@ -5714,6 +5797,19 @@
             }
         }, pkgFilter);
 
+        IntentFilter dumpheapFilter = new IntentFilter();
+        dumpheapFilter.addAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getBooleanExtra(DumpHeapActivity.EXTRA_DELAY_DELETE, false)) {
+                    mHandler.sendEmptyMessageDelayed(POST_DUMP_HEAP_NOTIFICATION_MSG, 5*60*1000);
+                } else {
+                    mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+                }
+            }
+        }, dumpheapFilter);
+
         // Let system services know.
         mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -7782,7 +7878,7 @@
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskThumbnail()");
-            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id, false);
+            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id);
             if (tr != null) {
                 return tr.getTaskThumbnailLocked();
             }
@@ -7895,7 +7991,7 @@
     @Override
     public void setTaskResizeable(int taskId, boolean resizeable) {
         synchronized (this) {
-            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, false);
+            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
             if (task == null) {
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
                 return;
@@ -8062,7 +8158,7 @@
      * @return Returns true if the given task was found and removed.
      */
     private boolean removeTaskByIdLocked(int taskId, boolean killProcess) {
-        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
+        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
         if (tr != null) {
             tr.removeTaskActivitiesLocked();
             cleanUpRemovedTaskLocked(tr, killProcess);
@@ -8315,7 +8411,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
+                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
                 return tr != null && tr.stack != null && tr.stack.isHomeStack();
             }
         } finally {
@@ -8347,6 +8443,9 @@
         synchronized (this) {
             pkg = task.intent.getComponent().getPackageName();
         }
+        // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode
+        // is initiated by system after the pinning request was shown and locked mode is initiated
+        // by an authorized app directly
         boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
         if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {
             StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -8367,7 +8466,9 @@
                                     || (task != mStackSupervisor.getFocusedStack().topTask()))) {
                         throw new IllegalArgumentException("Invalid task, not in foreground");
                     }
-                    mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated,
+                    mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
+                            ActivityManager.LOCK_TASK_MODE_PINNED :
+                            ActivityManager.LOCK_TASK_MODE_LOCKED,
                             "startLockTask");
                 }
             }
@@ -8453,7 +8554,8 @@
             Log.d(TAG, "stopLockTaskMode");
             // Stop lock task
             synchronized (this) {
-                mStackSupervisor.setLockTaskModeLocked(null, false, "stopLockTask");
+                mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+                        "stopLockTask");
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -8474,8 +8576,13 @@
 
     @Override
     public boolean isInLockTaskMode() {
+        return getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE;
+    }
+
+    @Override
+    public int getLockTaskModeState() {
         synchronized (this) {
-            return mStackSupervisor.isInLockTaskMode();
+            return mStackSupervisor.getLockTaskModeState();
         }
     }
 
@@ -12728,6 +12835,22 @@
                         + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
             }
         }
+        if (mMemWatchProcesses.size() > 0) {
+            pw.println("  Mem watch processes:");
+            for (int i=0; i<mMemWatchProcesses.size(); i++) {
+                if (needSep) {
+                    pw.println();
+                    needSep = false;
+                }
+                pw.print("    "); pw.print(mMemWatchProcesses.keyAt(i));
+                pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i));
+                pw.println();
+            }
+            pw.print("  mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
+            pw.print("  mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
+            pw.print("  mMemWatchDumpPid="); pw.print(mMemWatchDumpPid);
+                    pw.print(" mMemWatchDumpUid="); pw.println(mMemWatchDumpUid);
+        }
         if (mOpenGlTraceApp != null) {
             if (dumpPackage == null || dumpPackage.equals(mOpenGlTraceApp)) {
                 if (needSep) {
@@ -13410,8 +13533,9 @@
                 pw.print("    ");
                 pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
                 pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
-                pw.print(" lastPss="); pw.print(r.lastPss);
-                pw.print(" lastCachedPss="); pw.println(r.lastCachedPss);
+                pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
+                pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024);
+                pw.println();
                 pw.print(prefix);
                 pw.print("    ");
                 pw.print("cached="); pw.print(r.cached);
@@ -17219,7 +17343,7 @@
     /**
      * Record new PSS sample for a process.
      */
-    void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) {
+    void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
         EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
         proc.lastPssTime = now;
         proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
@@ -17233,6 +17357,67 @@
         if (procState >= ActivityManager.PROCESS_STATE_HOME) {
             proc.lastCachedPss = pss;
         }
+
+        Long check = mMemWatchProcesses.get(proc.processName);
+        if (check != null) {
+            if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+                boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+                if (!isDebuggable) {
+                    if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+                        isDebuggable = true;
+                    }
+                }
+                if (isDebuggable) {
+                    Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
+                    final ProcessRecord myProc = proc;
+                    final File heapdumpFile = DumpHeapProvider.getJavaFile();
+                    mMemWatchDumpProcName = proc.processName;
+                    mMemWatchDumpFile = heapdumpFile.toString();
+                    mMemWatchDumpPid = proc.pid;
+                    mMemWatchDumpUid = proc.uid;
+                    BackgroundThread.getHandler().post(new Runnable() {
+                        @Override
+                        public void run() {
+                            revokeUriPermission(ActivityThread.currentActivityThread()
+                                            .getApplicationThread(),
+                                    DumpHeapActivity.JAVA_URI,
+                                    Intent.FLAG_GRANT_READ_URI_PERMISSION
+                                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                                    UserHandle.myUserId());
+                            ParcelFileDescriptor fd = null;
+                            try {
+                                heapdumpFile.delete();
+                                fd = ParcelFileDescriptor.open(heapdumpFile,
+                                        ParcelFileDescriptor.MODE_CREATE |
+                                                ParcelFileDescriptor.MODE_TRUNCATE |
+                                                ParcelFileDescriptor.MODE_READ_WRITE);
+                                IApplicationThread thread = myProc.thread;
+                                if (thread != null) {
+                                    try {
+                                        if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from "
+                                                + myProc + " to " + heapdumpFile);
+                                        thread.dumpHeap(true, heapdumpFile.toString(), fd);
+                                    } catch (RemoteException e) {
+                                    }
+                                }
+                            } catch (FileNotFoundException e) {
+                                e.printStackTrace();
+                            } finally {
+                                if (fd != null) {
+                                    try {
+                                        fd.close();
+                                    } catch (IOException e) {
+                                    }
+                                }
+                            }
+                        }
+                    });
+                } else {
+                    Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check
+                            + ", but debugging not enabled");
+                }
+            }
+        }
     }
 
     /**
@@ -17591,7 +17776,7 @@
                 // states, which well tend to give noisy data.
                 long start = SystemClock.uptimeMillis();
                 long pss = Debug.getPss(app.pid, mTmpLong, null);
-                recordPssSample(app, app.curProcState, pss, mTmpLong[0], now);
+                recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now);
                 mPendingPssProcesses.remove(app);
                 Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
                         + " to " + app.curProcState + ": "
@@ -18411,6 +18596,38 @@
         }
     }
 
+    @Override
+    public void setDumpHeapDebugLimit(String processName, long maxMemSize) {
+        enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
+                "setDumpHeapDebugLimit()");
+        synchronized (this) {
+            if (maxMemSize > 0) {
+                mMemWatchProcesses.put(processName, maxMemSize);
+                mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+            } else {
+                mMemWatchProcesses.remove(processName);
+            }
+        }
+    }
+
+    @Override
+    public void dumpHeapFinished(String path) {
+        synchronized (this) {
+            if (Binder.getCallingPid() != mMemWatchDumpPid) {
+                Slog.w(TAG, "dumpHeapFinished: Calling pid " + Binder.getCallingPid()
+                        + " does not match last pid " + mMemWatchDumpPid);
+                return;
+            }
+            if (mMemWatchDumpFile == null || !mMemWatchDumpFile.equals(path)) {
+                Slog.w(TAG, "dumpHeapFinished: Calling path " + path
+                        + " does not match last path " + mMemWatchDumpFile);
+                return;
+            }
+            if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path);
+            mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+        }
+    }
+
     /** In this method we try to acquire our lock to make sure that we have not deadlocked */
     public void monitor() {
         synchronized (this) { }
@@ -18534,7 +18751,8 @@
                     return true;
                 }
 
-                mStackSupervisor.setLockTaskModeLocked(null, false, "startUser");
+                mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+                        "startUser");
 
                 final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
                 if (userInfo == null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 40a8b86..a1d99e3 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4247,8 +4247,6 @@
                 mActivityContainer.onTaskListEmptyLocked();
             }
         }
-
-        task.stack = null;
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a260330..62db20a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -20,6 +20,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.localLOGV;
 import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS;
@@ -116,7 +117,7 @@
 import java.util.List;
 
 public final class ActivityStackSupervisor implements DisplayListener {
-    static final boolean DEBUG = ActivityManagerService.DEBUG || false;
+    static final boolean DEBUG = DEBUG_ALL || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
     static final boolean DEBUG_APP = DEBUG || false;
     static final boolean DEBUG_CONTAINERS = DEBUG || false;
@@ -267,9 +268,11 @@
     /** If non-null then the task specified remains in front and no other tasks may be started
      * until the task exits or #stopLockTaskMode() is called. */
     TaskRecord mLockTaskModeTask;
-    /** Whether lock task has been entered by an authorized app and cannot
-     * be exited. */
-    private boolean mLockTaskIsLocked;
+    /** Store the current lock task mode. Possible values:
+     * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActicityManager#LOCK_TASK_MODE_LOCKED},
+     * {@link ActicityManager#LOCK_TASK_MODE_PINNED}
+     */
+    private int mLockTaskModeState;
     /**
      * Notifies the user when entering/exiting lock-task.
      */
@@ -468,16 +471,6 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
-        return anyTaskForIdLocked(id, true);
-    }
-
-    /**
-     * Returns a {@link TaskRecord} for the input id if available. Null otherwise.
-     * @param id Id of the task we would like returned.
-     * @param restoreFromRecents If the id was not in the active list, but was found in recents,
-     *                           restore the task from recents to the active list.
-     */
-    TaskRecord anyTaskForIdLocked(int id, boolean restoreFromRecents) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -498,10 +491,6 @@
             return null;
         }
 
-        if (!restoreFromRecents) {
-            return task;
-        }
-
         if (!restoreRecentTaskLocked(task)) {
             if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
             return null;
@@ -536,7 +525,7 @@
             if (mCurTaskId <= 0) {
                 mCurTaskId = 1;
             }
-        } while (anyTaskForIdLocked(mCurTaskId, false) != null);
+        } while (anyTaskForIdLocked(mCurTaskId) != null);
         return mCurTaskId;
     }
 
@@ -2728,7 +2717,7 @@
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack tmpStack = homeDisplayStacks.get(stackNdx);
-                if (!tmpStack.isHomeStack() && tmpStack.mFullscreen) {
+                if (!tmpStack.isHomeStack()) {
                     stack = tmpStack;
                     break;
                 }
@@ -3546,10 +3535,10 @@
     }
 
     void showLockTaskToast() {
-        mLockTaskNotify.showToast(mLockTaskIsLocked);
+        mLockTaskNotify.showToast(mLockTaskModeState);
     }
 
-    void setLockTaskModeLocked(TaskRecord task, boolean isLocked, String reason) {
+    void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) {
         if (task == null) {
             // Take out of lock task mode if necessary
             if (mLockTaskModeTask != null) {
@@ -3573,7 +3562,7 @@
         lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName();
         lockTaskMsg.arg1 = mLockTaskModeTask.userId;
         lockTaskMsg.what = LOCK_TASK_START_MSG;
-        lockTaskMsg.arg2 = !isLocked ? 1 : 0;
+        lockTaskMsg.arg2 = lockTaskModeState;
         mHandler.sendMessage(lockTaskMsg);
     }
 
@@ -3591,8 +3580,8 @@
         }
     }
 
-    boolean isInLockTaskMode() {
-        return mLockTaskModeTask != null;
+    int getLockTaskModeState() {
+        return mLockTaskModeState;
     }
 
     private final class ActivityStackSupervisorHandler extends Handler {
@@ -3684,13 +3673,18 @@
                             mLockTaskNotify = new LockTaskNotify(mService.mContext);
                         }
                         mLockTaskNotify.show(true);
-                        mLockTaskIsLocked = msg.arg2 == 0;
+                        mLockTaskModeState = msg.arg2;
                         if (getStatusBarService() != null) {
-                            int flags =
-                                    StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
-                            if (!mLockTaskIsLocked) {
-                                flags ^= StatusBarManager.DISABLE_HOME
-                                        | StatusBarManager.DISABLE_RECENT;
+                            int flags = 0;
+                            if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+                                flags = StatusBarManager.DISABLE_MASK
+                                        & (~StatusBarManager.DISABLE_BACK);
+                            } else if (mLockTaskModeState ==
+                                    ActivityManager.LOCK_TASK_MODE_PINNED) {
+                                flags = StatusBarManager.DISABLE_MASK
+                                        & (~StatusBarManager.DISABLE_BACK)
+                                        & (~StatusBarManager.DISABLE_HOME)
+                                        & (~StatusBarManager.DISABLE_RECENT);
                             }
                             getStatusBarService().disable(flags, mToken,
                                     mService.mContext.getPackageName());
@@ -3724,7 +3718,8 @@
                             boolean shouldLockKeyguard = Settings.Secure.getInt(
                                     mService.mContext.getContentResolver(),
                                     Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
-                            if (!mLockTaskIsLocked && shouldLockKeyguard) {
+                            if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED &&
+                                    shouldLockKeyguard) {
                                 mWindowManager.lockNow(null);
                                 mWindowManager.dismissKeyguard();
                                 new LockPatternUtils(mService.mContext)
@@ -3735,6 +3730,8 @@
                         }
                     } catch (RemoteException ex) {
                         throw new RuntimeException(ex);
+                    } finally {
+                        mLockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE;
                     }
                 } break;
                 case CONTAINER_CALLBACK_TASK_LIST_EMPTY: {
@@ -3982,10 +3979,6 @@
         }
 
         void onTaskListEmptyLocked() {
-            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
-            detachLocked();
-            deleteActivityContainer(this);
-            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
         }
 
         @Override
@@ -4074,6 +4067,13 @@
             return false;
         }
 
+        void onTaskListEmptyLocked() {
+            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+            detachLocked();
+            deleteActivityContainer(this);
+            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
+        }
+
         private void setSurfaceIfReadyLocked() {
             if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5083b1d..8fe1238 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -41,6 +41,8 @@
 import android.util.EventLog;
 import android.util.Slog;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
 /**
  * BROADCASTS
  *
@@ -48,11 +50,9 @@
  * foreground priority, and one for normal (background-priority) broadcasts.
  */
 public final class BroadcastQueue {
-    static final String TAG = "BroadcastQueue";
-    static final String TAG_MU = ActivityManagerService.TAG_MU;
-    static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
-    static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
-    static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "BroadcastQueue" : TAG_AM;
+    private static final String TAG_MU = TAG + POSTFIX_MU;
+    private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
 
     static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
     static final int MAX_BROADCAST_SUMMARY_HISTORY
@@ -143,7 +143,7 @@
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
                     if (DEBUG_BROADCAST) Slog.v(
-                            TAG, "Received BROADCAST_INTENT_MSG");
+                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                     processNextBroadcast(true);
                 } break;
                 case BROADCAST_TIMEOUT_MSG: {
@@ -196,7 +196,7 @@
     public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
         for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
             if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "***** DROPPING PARALLEL ["
                 + mQueueName + "]: " + r.intent);
                 mParallelBroadcasts.set(i, r);
@@ -209,7 +209,7 @@
     public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
         for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
             if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "***** DROPPING ORDERED ["
                         + mQueueName + "]: " + r.intent);
                 mOrderedBroadcasts.set(i, r);
@@ -221,7 +221,7 @@
 
     private final void processCurBroadcastLocked(BroadcastRecord r,
             ProcessRecord app) throws RemoteException {
-        if (DEBUG_BROADCAST)  Slog.v(TAG,
+        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                 "Process cur broadcast " + r + " for app " + app);
         if (app.thread == null) {
             throw new RemoteException();
@@ -238,7 +238,7 @@
 
         boolean started = false;
         try {
-            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
+            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                     "Delivering to component " + r.curComponent
                     + ": " + r);
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
@@ -246,12 +246,12 @@
                     mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                     r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                     app.repProcState);
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
+            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                     "Process cur broadcast " + r + " DELIVERED for app " + app);
             started = true;
         } finally {
             if (!started) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Process cur broadcast " + r + ": NOT STARTED!");
                 r.receiver = null;
                 r.curApp = null;
@@ -305,23 +305,22 @@
                     r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
-
-        r = mPendingBroadcast;
-        if (r != null && r.curApp == app) {
-            if (DEBUG_BROADCAST) Slog.v(TAG,
+        if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                     "[" + mQueueName + "] skip & discard pending app " + r);
+            r = mPendingBroadcast;
+        }
+
+        if (r != null) {
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
                     r.resultExtras, r.resultAbort, false);
-            reschedule = true;
-        }
-        if (reschedule) {
             scheduleBroadcastsLocked();
         }
     }
 
     public void scheduleBroadcastsLocked() {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                 + mQueueName + "]: current="
                 + mBroadcastsScheduled);
 
@@ -391,8 +390,7 @@
                 // on.  If there are background services currently starting, then we will go into a
                 // special state where we hold off on continuing this broadcast until they are done.
                 if (mService.mServices.hasBackgroundServices(r.userId)) {
-                    Slog.i(ActivityManagerService.TAG, "Delay finish: "
-                            + r.curComponent.flattenToShortString());
+                    Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
                     r.state = BroadcastRecord.WAITING_SERVICES;
                     return false;
                 }
@@ -412,7 +410,7 @@
         if (mOrderedBroadcasts.size() > 0) {
             BroadcastRecord br = mOrderedBroadcasts.get(0);
             if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
-                Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+                Slog.i(TAG, "Resuming delayed broadcast");
                 br.curComponent = null;
                 br.state = BroadcastRecord.IDLE;
                 processNextBroadcast(false);
@@ -475,7 +473,7 @@
             int mode = mService.mAppOpsService.noteOperation(r.appOp,
                     filter.receiverList.uid, filter.packageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "App op " + r.appOp + " not allowed for broadcast to uid "
                         + filter.receiverList.uid + " pkg " + filter.packageName);
                 skip = true;
@@ -513,10 +511,11 @@
                 }
             }
             try {
-                if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG, "Delivering to " + filter + " : " + r);
+                if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
+                        "Delivering to " + filter + " : " + r);
                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
-                    new Intent(r.intent), r.resultCode, r.resultData,
-                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
+                        new Intent(r.intent), r.resultCode, r.resultData,
+                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
                 if (ordered) {
                     r.state = BroadcastRecord.CALL_DONE_RECEIVE;
                 }
@@ -538,7 +537,7 @@
         synchronized(mService) {
             BroadcastRecord r;
 
-            if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
                     + mQueueName + "]: "
                     + mParallelBroadcasts.size() + " broadcasts, "
                     + mOrderedBroadcasts.size() + " ordered broadcasts");
@@ -555,17 +554,17 @@
                 r.dispatchTime = SystemClock.uptimeMillis();
                 r.dispatchClockTime = System.currentTimeMillis();
                 final int N = r.receivers.size();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                         + mQueueName + "] " + r);
                 for (int i=0; i<N; i++) {
                     Object target = r.receivers.get(i);
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                             "Delivering non-ordered on [" + mQueueName + "] to registered "
                             + target + ": " + r);
                     deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
                 }
                 addBroadcastToHistoryLocked(r);
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                         + mQueueName + "] " + r);
             }
 
@@ -575,11 +574,9 @@
             // broadcast, then do nothing at this point.  Just in case, we
             // check that the process we're waiting for still exists.
             if (mPendingBroadcast != null) {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    Slog.v(TAG, "processNextBroadcast ["
-                            + mQueueName + "]: waiting for "
-                            + mPendingBroadcast.curApp);
-                }
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+                        "processNextBroadcast [" + mQueueName + "]: waiting for "
+                        + mPendingBroadcast.curApp);
 
                 boolean isDead;
                 synchronized (mService.mPidsSelfLocked) {
@@ -645,7 +642,7 @@
                 }
 
                 if (r.state != BroadcastRecord.IDLE) {
-                    if (DEBUG_BROADCAST) Slog.d(TAG,
+                    if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                             "processNextBroadcast("
                             + mQueueName + ") called when not idle (state="
                             + r.state + ")");
@@ -658,7 +655,7 @@
                     // result if requested...
                     if (r.resultTo != null) {
                         try {
-                            if (DEBUG_BROADCAST) Slog.i(TAG,
+                            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                                     "Finishing broadcast [" + mQueueName + "] "
                                     + r.intent.getAction() + " app=" + r.callerApp);
                             performReceiveLocked(r.callerApp, r.resultTo,
@@ -675,11 +672,11 @@
                         }
                     }
 
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
                     cancelBroadcastTimeoutLocked();
 
-                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
-                            + r);
+                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+                            "Finished with ordered broadcast " + r);
 
                     // ... and on to the next...
                     addBroadcastToHistoryLocked(r);
@@ -699,12 +696,12 @@
             if (recIdx == 0) {
                 r.dispatchTime = r.receiverTime;
                 r.dispatchClockTime = System.currentTimeMillis();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
                         + mQueueName + "] " + r);
             }
             if (! mPendingBroadcastTimeoutMessage) {
                 long timeoutTime = r.receiverTime + mTimeoutPeriod;
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "Submitting BROADCAST_TIMEOUT_MSG ["
                         + mQueueName + "] for " + r + " at " + timeoutTime);
                 setBroadcastTimeoutLocked(timeoutTime);
@@ -715,7 +712,7 @@
                 // Simple case: this is a registered receiver who gets
                 // a direct call.
                 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Delivering ordered ["
                         + mQueueName + "] to registered "
                         + filter + ": " + r);
@@ -723,7 +720,7 @@
                 if (r.receiver == null || !r.ordered) {
                     // The receiver has already finished, so schedule to
                     // process the next one.
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                             + mQueueName + "]: ordered="
                             + r.ordered + " receiver=" + r.receiver);
                     r.state = BroadcastRecord.IDLE;
@@ -786,7 +783,7 @@
                 int mode = mService.mAppOpsService.noteOperation(r.appOp,
                         info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
                 if (mode != AppOpsManager.MODE_ALLOWED) {
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                             "App op " + r.appOp + " not allowed for broadcast to uid "
                             + info.activityInfo.applicationInfo.uid + " pkg "
                             + info.activityInfo.packageName);
@@ -835,19 +832,18 @@
                             + info.activityInfo.packageName, e);
                 }
                 if (!isAvailable) {
-                    if (DEBUG_BROADCAST) {
-                        Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
-                                + " / " + info.activityInfo.applicationInfo.uid
-                                + " : package no longer available");
-                    }
+                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
+                            "Skipping delivery to " + info.activityInfo.packageName + " / "
+                            + info.activityInfo.applicationInfo.uid
+                            + " : package no longer available");
                     skip = true;
                 }
             }
 
             if (skip) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Skipping delivery of ordered ["
-                        + mQueueName + "] " + r + " for whatever reason");
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
+                        "Skipping delivery of ordered [" + mQueueName + "] "
+                        + r + " for whatever reason");
                 r.receiver = null;
                 r.curFilter = null;
                 r.state = BroadcastRecord.IDLE;
@@ -915,7 +911,7 @@
             }
 
             // Not running -- get it started, to be executed when the app comes up.
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
+            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                     "Need to start app ["
                     + mQueueName + "] " + targetProcess + " for broadcast " + r);
             if ((r.curApp=mService.startProcessLocked(targetProcess,
@@ -990,7 +986,7 @@
                 // broadcast timeout message after each receiver finishes.  Instead, we set up
                 // an initial timeout then kick it down the road a little further as needed
                 // when it expires.
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "Premature timeout ["
                         + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
                         + timeoutTime);
@@ -1005,7 +1001,7 @@
             // for started services to finish as well before going on.  So if we have actually
             // waited long enough time timeout the broadcast, let's give up on the whole thing
             // and just move on to the next.
-            Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+            Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
                     ? br.curComponent.flattenToShortString() : "(null)"));
             br.curComponent = null;
             br.state = BroadcastRecord.IDLE;
diff --git a/services/core/java/com/android/server/am/DumpHeapProvider.java b/services/core/java/com/android/server/am/DumpHeapProvider.java
new file mode 100644
index 0000000..a8b639e
--- /dev/null
+++ b/services/core/java/com/android/server/am/DumpHeapProvider.java
@@ -0,0 +1,89 @@
+/*
+ * 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.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class DumpHeapProvider extends ContentProvider {
+    static final Object sLock = new Object();
+    static File sHeapDumpJavaFile;
+
+    static public File getJavaFile() {
+        synchronized (sLock) {
+            return sHeapDumpJavaFile;
+        }
+    }
+
+    @Override
+    public boolean onCreate() {
+        synchronized (sLock) {
+            File dataDir = Environment.getDataDirectory();
+            File systemDir = new File(dataDir, "system");
+            File heapdumpDir = new File(systemDir, "heapdump");
+            heapdumpDir.mkdir();
+            sHeapDumpJavaFile = new File(heapdumpDir, "javaheap.bin");
+        }
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return "application/octet-stream";
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        synchronized (sLock) {
+            String path = uri.getEncodedPath();
+            final String tag = Uri.decode(path);
+            if (tag.equals("/java")) {
+                return ParcelFileDescriptor.open(sHeapDumpJavaFile,
+                        ParcelFileDescriptor.MODE_READ_ONLY);
+            } else {
+                throw new FileNotFoundException("Invalid path for " + uri);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index b3777ed..afde322 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
@@ -44,15 +45,20 @@
         mHandler = new H();
     }
 
-    public void showToast(boolean isLocked) {
-        mHandler.obtainMessage(H.SHOW_TOAST, isLocked ? 1 : 0, 0 /* Not used */).sendToTarget();
+    public void showToast(int lockTaskModeState) {
+        mHandler.obtainMessage(H.SHOW_TOAST, lockTaskModeState, 0 /* Not used */).sendToTarget();
     }
 
-    public void handleShowToast(boolean isLocked) {
-        String text = mContext.getString(isLocked
-                ? R.string.lock_to_app_toast_locked : R.string.lock_to_app_toast);
-        if (!isLocked && mAccessibilityManager.isEnabled()) {
-            text = mContext.getString(R.string.lock_to_app_toast_accessible);
+    public void handleShowToast(int lockTaskModeState) {
+        String text = null;
+        if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+            text = mContext.getString(R.string.lock_to_app_toast_locked);
+        } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) {
+            text = mContext.getString(mAccessibilityManager.isEnabled()
+                    ? R.string.lock_to_app_toast_accessible : R.string.lock_to_app_toast);
+        }
+        if (text == null) {
+            return;
         }
         if (mLastToast != null) {
             mLastToast.cancel();
@@ -83,7 +89,7 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case SHOW_TOAST:
-                    handleShowToast(msg.arg1 != 0);
+                    handleShowToast(msg.arg1);
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a6c616a..f374c86 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.EventLog;
 import android.util.Slog;
 import com.android.internal.app.ProcessStats;
@@ -248,8 +249,9 @@
                 pw.println();
         pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                 pw.print(" lruSeq="); pw.print(lruSeq);
-                pw.print(" lastPss="); pw.print(lastPss);
-                pw.print(" lastCachedPss="); pw.println(lastCachedPss);
+                pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024);
+                pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
+                pw.println();
         pw.print(prefix); pw.print("cached="); pw.print(cached);
                 pw.print(" empty="); pw.println(empty);
         if (serviceb) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 018d77a..fc949e0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -141,6 +141,9 @@
     /** debug calls to media session apis */
     private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
 
+    /** debug calls to devices APIs */
+    protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
+
     /** Allow volume changes to set ringer mode to silent? */
     private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
 
@@ -188,7 +191,6 @@
     // AudioHandler messages
     private static final int MSG_SET_DEVICE_VOLUME = 0;
     private static final int MSG_PERSIST_VOLUME = 1;
-    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
     private static final int MSG_PERSIST_RINGER_MODE = 3;
     private static final int MSG_MEDIA_SERVER_DIED = 4;
     private static final int MSG_PLAY_SOUND_EFFECT = 5;
@@ -239,10 +241,6 @@
     private final Object mSoundEffectsLock = new Object();
     private static final int NUM_SOUNDPOOL_CHANNELS = 4;
 
-    // Internally master volume is a float in the 0.0 - 1.0 range,
-    // but to support integer based AudioManager API we translate it to 0 - 100
-    private static final int MAX_MASTER_VOLUME = 100;
-
     // Maximum volume adjust steps allowed in a single batch call.
     private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
 
@@ -381,16 +379,36 @@
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
 
     // Devices currently connected
-    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+    // Use makeDeviceListKey() to make a unique key for this list.
+    private class DeviceListSpec {
+        int mDeviceType;
+        String mDeviceName;
+        String mDeviceAddress;
+
+        public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
+            mDeviceType = deviceType;
+            mDeviceName = deviceName;
+            mDeviceAddress = deviceAddress;
+        }
+
+        public String toString() {
+            return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
+                    + " address:" + mDeviceAddress + "]";
+        }
+    }
+
+    // Generate a unique key for the mConnectedDevices List by composing the device "type"
+    // and the "address" associated with a specific instance of that device type
+    private String makeDeviceListKey(int device, String deviceAddress) {
+        return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
+    }
+
+    private final HashMap<String, DeviceListSpec> mConnectedDevices =
+            new HashMap<String, DeviceListSpec>();
 
     // Forced device usage for communications
     private int mForcedUseForComm;
 
-    // True if we have master volume support
-    private final boolean mUseMasterVolume;
-
-    private final int[] mMasterVolumeRamp;
-
     // List of binder death handlers for setMode() client processes.
     // The last process to have called setMode() is at the top of the list.
     private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
@@ -530,6 +548,8 @@
         return "card=" + card + ";device=" + device + ";";
     }
 
+    private final String DEVICE_NAME_A2DP = "a2dp-device";
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -595,10 +615,6 @@
 
         mUseFixedVolume = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useFixedVolume);
-        mUseMasterVolume = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
-        mMasterVolumeRamp = context.getResources().getIntArray(
-                com.android.internal.R.array.config_masterVolumeRamp);
 
         // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
         // array initialized by updateStreamVolumeAlias()
@@ -647,8 +663,6 @@
 
         context.registerReceiver(mReceiver, intentFilter);
 
-        restoreMasterVolume();
-
         LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
     }
 
@@ -882,7 +896,7 @@
                 UserHandle.USER_CURRENT);
 
         boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
-                                                  0, UserHandle.USER_CURRENT) == 1;
+                0, UserHandle.USER_CURRENT) == 1;
         if (mUseFixedVolume) {
             masterMute = false;
             AudioSystem.setMasterVolume(1.0f);
@@ -1050,7 +1064,7 @@
         // If either the client forces allowing ringer modes for this adjustment,
         // or the stream type is one that is affected by ringer modes
         if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
-                (streamTypeAlias == getMasterStreamType())) {
+                (streamTypeAlias == getUiSoundsStreamType())) {
             int ringerMode = getRingerModeInternal();
             // do not vibrate if already in vibrate mode
             if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
@@ -1183,33 +1197,6 @@
         }
     }
 
-    /** @see AudioManager#adjustMasterVolume(int, int) */
-    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
-        adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
-    }
-
-    public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        if (isMuteAdjust(steps)) {
-            setMasterMuteInternal(steps, flags, callingPackage, uid);
-            return;
-        }
-        ensureValidSteps(steps);
-        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
-        int delta = 0;
-        int numSteps = Math.abs(steps);
-        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
-        for (int i = 0; i < numSteps; ++i) {
-            delta = findVolumeDelta(direction, volume);
-            volume += delta;
-        }
-
-        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
-        setMasterVolume(volume, flags, callingPackage, uid);
-    }
-
     // StreamVolumeCommand contains the information needed to defer the process of
     // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
     class StreamVolumeCommand {
@@ -1235,9 +1222,9 @@
 
     private void onSetStreamVolume(int streamType, int index, int flags, int device) {
         setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
-        // setting volume on master stream type also controls silent mode
+        // setting volume on ui sounds stream type also controls silent mode
         if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
-                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
+                (mStreamVolumeAlias[streamType] == getUiSoundsStreamType())) {
             int newRingerMode;
             if (index == 0) {
                 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
@@ -1381,41 +1368,6 @@
         }
     }
 
-    private int findVolumeDelta(int direction, int volume) {
-        int delta = 0;
-        if (direction == AudioManager.ADJUST_RAISE) {
-            if (volume == MAX_MASTER_VOLUME) {
-                return 0;
-            }
-            // This is the default value if we make it to the end
-            delta = mMasterVolumeRamp[1];
-            // If we're raising the volume move down the ramp array until we
-            // find the volume we're above and use that groups delta.
-            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
-                if (volume >= mMasterVolumeRamp[i - 1]) {
-                    delta = mMasterVolumeRamp[i];
-                    break;
-                }
-            }
-        } else if (direction == AudioManager.ADJUST_LOWER){
-            if (volume == 0) {
-                return 0;
-            }
-            int length = mMasterVolumeRamp.length;
-            // This is the default value if we make it to the end
-            delta = -mMasterVolumeRamp[length - 1];
-            // If we're lowering the volume move up the ramp array until we
-            // find the volume we're below and use the group below it's delta
-            for (int i = 2; i < length; i += 2) {
-                if (volume <= mMasterVolumeRamp[i]) {
-                    delta = -mMasterVolumeRamp[i - 1];
-                    break;
-                }
-            }
-        }
-        return delta;
-    }
-
     private void sendBroadcastToAll(Intent intent) {
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -1464,16 +1416,6 @@
     }
 
     // UI update and Broadcast Intent
-    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
-        mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
-
-        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
-        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
-        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
-        sendBroadcastToAll(intent);
-    }
-
-    // UI update and Broadcast Intent
     private void sendMasterMuteUpdate(boolean muted, int flags) {
         mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
         broadcastMasterMuteStatus(muted);
@@ -1641,27 +1583,21 @@
         }
     }
 
-    private void setMasterMuteInternal(int adjust, int flags, String callingPackage, int uid) {
+    private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid) {
         if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
                 != AppOpsManager.MODE_ALLOWED) {
             return;
         }
-        boolean state;
-        if (adjust == AudioManager.ADJUST_TOGGLE_MUTE) {
-            state = !AudioSystem.getMasterMute();
-        } else {
-            state = adjust == AudioManager.ADJUST_MUTE;
-        }
-        if (state != AudioSystem.getMasterMute()) {
-            setSystemAudioMute(state);
-            AudioSystem.setMasterMute(state);
+        if (mute != AudioSystem.getMasterMute()) {
+            setSystemAudioMute(mute);
+            AudioSystem.setMasterMute(mute);
             // Post a persist master volume msg
-            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
+            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
                     : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
-            sendMasterMuteUpdate(state, flags);
+            sendMasterMuteUpdate(mute, flags);
 
             Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
-            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
+            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
             sendBroadcastToAll(intent);
         }
     }
@@ -1671,6 +1607,10 @@
         return AudioSystem.getMasterMute();
     }
 
+    public void setMasterMute(boolean mute, int flags, String callingPackage) {
+        setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid());
+    }
+
     protected static int getMaxStreamVolume(int streamType) {
         return MAX_STREAM_VOLUME[streamType];
     }
@@ -1694,63 +1634,12 @@
         }
     }
 
-    @Override
-    public int getMasterVolume() {
-        if (isMasterMute()) return 0;
-        return getLastAudibleMasterVolume();
-    }
-
-    @Override
-    public void setMasterVolume(int volume, int flags, String callingPackage) {
-        setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
-    }
-
-    public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
-
-        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
-            return;
-        }
-
-        if (volume < 0) {
-            volume = 0;
-        } else if (volume > MAX_MASTER_VOLUME) {
-            volume = MAX_MASTER_VOLUME;
-        }
-        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
-    }
-
-    private void doSetMasterVolume(float volume, int flags) {
-        // don't allow changing master volume when muted
-        if (!AudioSystem.getMasterMute()) {
-            int oldVolume = getMasterVolume();
-            AudioSystem.setMasterVolume(volume);
-
-            int newVolume = getMasterVolume();
-            if (newVolume != oldVolume) {
-                // Post a persist master volume msg
-                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
-                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
-                setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
-            }
-            // Send the volume update regardless whether there was a change.
-            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
-        }
-    }
-
     /** @see AudioManager#getStreamMaxVolume(int) */
     public int getStreamMaxVolume(int streamType) {
         ensureValidStreamType(streamType);
         return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
     }
 
-    public int getMasterMaxVolume() {
-        return MAX_MASTER_VOLUME;
-    }
-
     /** Get last audible volume before stream was muted. */
     public int getLastAudibleStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
@@ -1758,13 +1647,8 @@
         return (mStreamStates[streamType].getIndex(device) + 5) / 10;
     }
 
-    /** Get last audible master volume before it was muted. */
-    public int getLastAudibleMasterVolume() {
-        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
-    }
-
-    /** @see AudioManager#getMasterStreamType()  */
-    public int getMasterStreamType() {
+    /** @see AudioManager#getUiSoundsStreamType()  */
+    public int getUiSoundsStreamType() {
         return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
     }
 
@@ -1932,20 +1816,6 @@
         }
     }
 
-    private void restoreMasterVolume() {
-        if (mUseFixedVolume) {
-            AudioSystem.setMasterVolume(1.0f);
-            return;
-        }
-        if (mUseMasterVolume) {
-            float volume = Settings.System.getFloatForUser(mContentResolver,
-                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
-            if (volume >= 0.0f) {
-                AudioSystem.setMasterVolume(volume);
-            }
-        }
-    }
-
     /** @see AudioManager#shouldVibrate(int) */
     public boolean shouldVibrate(int vibrateType) {
         if (!mHasVibrator) return false;
@@ -2927,14 +2797,17 @@
             }
         }
         public void onServiceDisconnected(int profile) {
-            switch(profile) {
+            switch (profile) {
             case BluetoothProfile.A2DP:
                 synchronized (mConnectedDevices) {
                     synchronized (mA2dpAvrcpLock) {
-                        mA2dp = null;
-                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
-                            makeA2dpDeviceUnavailableNow(
-                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
+                        // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
+                        for(Map.Entry<String, DeviceListSpec> entry
+                                : mConnectedDevices.entrySet()) {
+                            DeviceListSpec deviceSpec = entry.getValue();
+                            if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                                makeA2dpDeviceUnavailableNow(deviceSpec.mDeviceAddress);
+                            }
                         }
                     }
                 }
@@ -2942,9 +2815,13 @@
 
             case BluetoothProfile.A2DP_SINK:
                 synchronized (mConnectedDevices) {
-                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
-                        makeA2dpSrcUnavailable(
-                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
+                    // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
+                    for(Map.Entry<String, DeviceListSpec> entry
+                            : mConnectedDevices.entrySet()) {
+                        DeviceListSpec deviceSpec = entry.getValue();
+                        if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
+                            makeA2dpSrcUnavailable(deviceSpec.mDeviceAddress);
+                        }
                     }
                 }
                 break;
@@ -3432,6 +3309,10 @@
     public void setWiredDeviceConnectionState(int type, int state, String address,
             String name) {
         synchronized (mConnectedDevices) {
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
+                        + address + ")");
+            }
             int delay = checkSendBecomingNoisyIntent(type, state);
             queueMsgUnderWakeLock(mAudioHandler,
                     MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
@@ -3510,9 +3391,8 @@
 
         public void readSettings() {
             synchronized (VolumeStreamState.class) {
-                // force maximum volume on all streams if fixed volume property
-                // or master volume property is set
-                if (mUseFixedVolume || mUseMasterVolume) {
+                // force maximum volume on all streams if fixed volume property is set
+                if (mUseFixedVolume) {
                     mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
                     return;
                 }
@@ -3747,7 +3627,7 @@
         private int getValidIndex(int index) {
             if (index < 0) {
                 return 0;
-            } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
+            } else if (mUseFixedVolume || index > mIndexMax) {
                 return mIndexMax;
             }
 
@@ -3777,6 +3657,21 @@
                 final int index = (mIndexMap.valueAt(i) + 5) / 10;
                 pw.print(index);
             }
+            pw.println();
+            pw.print("   Devices: ");
+            final int devices = AudioSystem.getDevicesForStream(mStreamType);
+            int device, i = 0, n = 0;
+            // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
+            // (the default device is not returned by getDevicesForStream)
+            while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
+                if ((devices & device) != 0) {
+                    if (n++ > 0) {
+                        pw.print(", ");
+                    }
+                    pw.print(AudioSystem.getOutputDeviceName(device));
+                }
+                i++;
+            }
         }
     }
 
@@ -4119,16 +4014,6 @@
                     persistVolume((VolumeStreamState) msg.obj, msg.arg1);
                     break;
 
-                case MSG_PERSIST_MASTER_VOLUME:
-                    if (mUseFixedVolume) {
-                        return;
-                    }
-                    Settings.System.putFloatForUser(mContentResolver,
-                                                    Settings.System.VOLUME_MASTER,
-                                                    msg.arg1 / (float)1000.0,
-                                                    UserHandle.USER_CURRENT);
-                    break;
-
                 case MSG_PERSIST_MASTER_VOLUME_MUTE:
                     if (mUseFixedVolume) {
                         return;
@@ -4197,9 +4082,6 @@
                     // Restore ringer mode
                     setRingerModeInt(getRingerModeInternal(), false);
 
-                    // Restore master volume
-                    restoreMasterVolume();
-
                     // Reset device orientation (if monitored for this device)
                     if (mMonitorOrientation) {
                         setOrientationForAudioSystem();
@@ -4395,13 +4277,13 @@
                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
         setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE,
-                address,
-                "a2dp-device");
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
         // Reset A2DP suspend state each time a new sink is connected
         AudioSystem.setParameters("A2dpSuspended=false");
-        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
-                address);
+        mConnectedDevices.put(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+                new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+                                   address));
     }
 
     private void onSendBecomingNoisyIntent() {
@@ -4414,10 +4296,9 @@
             mAvrcpAbsVolSupported = false;
         }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address,
-                "a2dp-device");
-        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         synchronized (mCurAudioRoutes) {
             // Remove A2DP routes as well
             if (mCurAudioRoutes.bluetoothName != null) {
@@ -4434,7 +4315,8 @@
         // reconnection of the sink.
         AudioSystem.setParameters("A2dpSuspended=true");
         // the device will be made unavailable later, so consider it disconnected right away
-        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // send the delayed message to make the device unavailable later
         Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
         mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
@@ -4444,20 +4326,19 @@
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcAvailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE,
-                address,
-                "a2dp-device");
-        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
-                address);
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.put(
+                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+                new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+                                   address));
     }
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcUnavailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address,
-                "a2dp-device");
-        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
     }
 
     // must be called synchronized on mConnectedDevices
@@ -4484,9 +4365,10 @@
         }
 
         synchronized (mConnectedDevices) {
-            boolean isConnected =
-                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
-                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
+            String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                           btDevice.getAddress());
+            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            boolean isConnected = deviceSpec != null;
 
             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
                 if (btDevice.isBluetoothDock()) {
@@ -4547,9 +4429,9 @@
         }
 
         synchronized (mConnectedDevices) {
-                boolean isConnected =
-                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
-                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
+            String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
+            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            boolean isConnected = deviceSpec != null;
 
             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
                 makeA2dpSrcUnavailable(address);
@@ -4572,27 +4454,32 @@
         }
     }
 
-    private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
-        Slog.i(TAG, "handleDeviceConnection(" + connect +
-                " dev:" + Integer.toHexString(device) +
-                " address:" + address +
-                " name:" + deviceName + ")");
+    private boolean handleDeviceConnection(boolean connect, int device, String address,
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
+                    + " address:" + address + " name:" + deviceName + ")");
+        }
         synchronized (mConnectedDevices) {
-            boolean isConnected = (mConnectedDevices.containsKey(device) &&
-                    (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
-
-            if (isConnected && !connect) {
-                AudioSystem.setDeviceConnectionState(device,
-                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                                              address, deviceName);
-                 mConnectedDevices.remove(device);
-                 return true;
-            } else if (!isConnected && connect) {
-                 AudioSystem.setDeviceConnectionState(device,
-                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
-                                                      address, deviceName);
-                 mConnectedDevices.put(new Integer(device), address);
-                 return true;
+            String deviceKey = makeDeviceListKey(device, address);
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "deviceKey:" + deviceKey);
+            }
+            DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
+            boolean isConnected = deviceSpec != null;
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
+            }
+            if (connect && !isConnected) {
+                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
+                        address, deviceName);
+                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
+                return true;
+            } else if (!connect && isConnected) {
+                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
+                        address, deviceName);
+                mConnectedDevices.remove(deviceKey);
+                return true;
             }
         }
         return false;
@@ -4613,10 +4500,11 @@
         int delay = 0;
         if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
             int devices = 0;
-            for (int dev : mConnectedDevices.keySet()) {
-                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
-                        ((dev & mBecomingNoisyIntentDevices) != 0)) {
-                   devices |= dev;
+            for (String key : mConnectedDevices.keySet()) {
+                int dev = mConnectedDevices.get(key).mDeviceType;
+                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
+                        && ((dev & mBecomingNoisyIntentDevices) != 0)) {
+                    devices |= dev;
                 }
             }
             if (devices == device) {
@@ -4644,12 +4532,13 @@
         return delay;
     }
 
-    private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
-    {
-        Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
-                " state:0x" + Integer.toHexString(state) +
-                " address:" + address +
-                " name:" + deviceName + ");");
+    private void sendDeviceConnectionIntent(int device, int state, String address,
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
+                    " state:0x" + Integer.toHexString(state) + " address:" + address +
+                    " name:" + deviceName + ");");
+        }
         Intent intent = new Intent();
 
         intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
@@ -4703,12 +4592,12 @@
     }
 
     private void onSetWiredDeviceConnectionState(int device, int state, String address,
-            String deviceName)
-    {
-        Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
-                + " state:" + Integer.toHexString(state)
-                + " address:" + address
-                + " deviceName:" + deviceName + ");");
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device) +
+                    " state:" + Integer.toHexString(state) + " address:" + address +
+                    " deviceName:" + deviceName + ");");
+        }
 
         synchronized (mConnectedDevices) {
             if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
@@ -5666,16 +5555,6 @@
             }
         }
 
-        public void postMasterVolumeChanged(int flags) {
-            if (mController == null)
-                return;
-            try {
-                mController.masterVolumeChanged(flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error calling masterVolumeChanged", e);
-            }
-        }
-
         public void postMasterMuteChanged(int flags) {
             if (mController == null)
                 return;
@@ -5741,12 +5620,6 @@
         }
 
         @Override
-        public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
-                int uid) {
-            adjustMasterVolume(steps, flags, callingPackage, uid);
-        }
-
-        @Override
         public int getRingerModeInternal() {
             return AudioService.this.getRingerModeInternal();
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 82c99f78..7c93e56 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -202,7 +202,6 @@
                 reason != HdmiControlService.INITIATED_BY_BOOT_UP);
         mLocalDeviceAddresses = initLocalDeviceAddresses();
         launchDeviceDiscovery();
-        startQueuedActions();
     }
 
 
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 3345e46..b5036db 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -90,14 +90,12 @@
     private final SessionStub mSession;
     private final SessionCb mSessionCb;
     private final MediaSessionService mService;
-    private final boolean mUseMasterVolume;
 
     private final Object mLock = new Object();
     private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
             new ArrayList<ISessionControllerCallback>();
 
     private long mFlags;
-    private IMediaRouter mMediaRouter;
     private PendingIntent mMediaButtonReceiver;
     private PendingIntent mLaunchIntent;
 
@@ -141,8 +139,6 @@
         mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
         mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
         mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
-        mUseMasterVolume = service.getContext().getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
     }
 
     /**
@@ -247,13 +243,6 @@
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
         }
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
-            if (mUseMasterVolume) {
-                // If this device only uses master volume and playback is local
-                // just adjust the master volume and return.
-                mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
-                        uid);
-                return;
-            }
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
             if (useSuggested) {
                 if (AudioSystem.isStreamActive(stream, 0)) {
@@ -729,7 +718,6 @@
 
         @Override
         public void setMediaRouter(IMediaRouter router) {
-            mMediaRouter = router;
             mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
         }
 
@@ -820,6 +808,7 @@
             }
             if (typeChanged) {
                 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
 
@@ -834,6 +823,7 @@
             }
             if (typeChanged) {
                 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4383bb1..72205d6 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -89,11 +89,9 @@
     private final Object mLock = new Object();
     private final MessageHandler mHandler = new MessageHandler();
     private final PowerManager.WakeLock mMediaEventWakeLock;
-    private final boolean mUseMasterVolume;
 
     private KeyguardManager mKeyguardManager;
     private IAudioService mAudioService;
-    private AudioManager mAudioManager;
     private AudioManagerInternal mAudioManagerInternal;
     private ContentResolver mContentResolver;
     private SettingsObserver mSettingsObserver;
@@ -110,8 +108,6 @@
         mPriorityStack = new MediaSessionStack();
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
-        mUseMasterVolume = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
     }
 
     @Override
@@ -121,7 +117,6 @@
         mKeyguardManager =
                 (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
         mAudioService = getAudioService();
-        mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
         mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
         mContentResolver = getContext().getContentResolver();
         mSettingsObserver = new SettingsObserver();
@@ -468,11 +463,6 @@
         return -1;
     }
 
-    private boolean isSessionDiscoverable(MediaSessionRecord record) {
-        // TODO probably want to check more than if it's active.
-        return record.isActive();
-    }
-
     private void pushSessionsChanged(int userId) {
         synchronized (mLock) {
             List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId);
@@ -889,12 +879,8 @@
                 }
                 try {
                     String packageName = getContext().getOpPackageName();
-                    if (mUseMasterVolume) {
-                            mAudioService.adjustMasterVolume(direction, flags, packageName);
-                    } else {
-                        mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
-                                flags, packageName);
-                    }
+                    mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
+                            flags, packageName);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error adjusting default volume.", e);
                 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9b6b5fb..bb0aa65c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1026,6 +1026,7 @@
     private void updateListenerHintsLocked() {
         final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
         if (hints == mListenerHints) return;
+        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
         mListenerHints = hints;
         scheduleListenerHintsChanged(hints);
     }
@@ -1034,6 +1035,7 @@
         final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
                 ? mListenersDisablingEffects.valueAt(0).component : null;
         if (Objects.equals(suppressor, mEffectsSuppressor)) return;
+        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
         mEffectsSuppressor = suppressor;
         mZenModeHelper.setEffectsSuppressed(suppressor != null);
         getContext().sendBroadcast(new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)
@@ -2584,8 +2586,8 @@
             @Override
             public void run() {
                 String listenerName = listener == null ? null : listener.component.toShortString();
-                EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId,
-                        mustHaveFlags, mustNotHaveFlags, reason, listenerName);
+                if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
+                        userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
 
                 synchronized (mNotificationList) {
                     int index = indexOfNotificationLocked(pkg, tag, id, userId);
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index a83fbc3..1fc967f 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -24,6 +24,7 @@
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.IConditionProvider;
+import android.service.notification.NotificationListenerService;
 import android.service.notification.ZenModeConfig;
 import android.util.Slog;
 
@@ -56,6 +57,8 @@
     private static final int TYPE_CONFIG = 11;
     private static final int TYPE_NOT_INTERCEPTED = 12;
     private static final int TYPE_DISABLE_EFFECTS = 13;
+    private static final int TYPE_SUPPRESSOR_CHANGED = 14;
+    private static final int TYPE_LISTENER_HINTS_CHANGED = 15;
 
     private static int sNext;
     private static int sSize;
@@ -120,6 +123,17 @@
         append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason);
     }
 
+    public static void traceEffectsSuppressorChanged(ComponentName oldSuppressor,
+            ComponentName newSuppressor) {
+        append(TYPE_SUPPRESSOR_CHANGED, componentToString(oldSuppressor) + "->"
+            + componentToString(newSuppressor));
+    }
+
+    public static void traceListenerHintsChanged(int oldHints, int newHints, int listenerCount) {
+        append(TYPE_LISTENER_HINTS_CHANGED, hintsToString(oldHints) + "->"
+            + hintsToString(newHints) + ",listeners=" + listenerCount);
+    }
+
     private static String subscribeResult(IConditionProvider provider, RemoteException e) {
         return provider == null ? "no provider" : e != null ? e.getMessage() : "ok";
     }
@@ -139,6 +153,8 @@
             case TYPE_CONFIG: return "config";
             case TYPE_NOT_INTERCEPTED: return "not_intercepted";
             case TYPE_DISABLE_EFFECTS: return "disable_effects";
+            case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed";
+            case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed";
             default: return "unknown";
         }
     }
@@ -161,6 +177,14 @@
         }
     }
 
+    private static String hintsToString(int hints) {
+        switch (hints) {
+            case 0 : return "none";
+            case NotificationListenerService.HINT_HOST_DISABLE_EFFECTS : return "disable_effects";
+            default: return Integer.toString(hints);
+        }
+    }
+
     private static String componentToString(ComponentName component) {
         return component != null ? component.toShortString() : null;
     }
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 773b164..aa63932 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -414,9 +414,9 @@
         // Get the package's known keys and KeySets
         ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
         ArraySet<Long> deletableKeys = new ArraySet<Long>();
-        ArraySet<Long> knownKeys = null;
-        for (Long ks : deletableKeySets) {
-            knownKeys = mKeySetMapping.get(ks);
+        final int origDksSize = deletableKeySets.size();
+        for (int i = 0; i < origDksSize; i++) {
+            ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i));
             if (knownKeys != null) {
                 deletableKeys.addAll(knownKeys);
             }
@@ -429,9 +429,9 @@
             }
             ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
             deletableKeySets.removeAll(knownKeySets);
-            knownKeys = new ArraySet<Long>();
-            for (Long ks : knownKeySets) {
-                knownKeys = mKeySetMapping.get(ks);
+            final int kksSize = knownKeySets.size();
+            for (int i = 0; i < kksSize; i++) {
+                ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i));
                 if (knownKeys != null) {
                     deletableKeys.removeAll(knownKeys);
                 }
@@ -440,18 +440,22 @@
 
         // The remaining keys and KeySets are not relied on by any other
         // application and so can be safely deleted.
-        for (Long ks : deletableKeySets) {
+        final int dksSize = deletableKeySets.size();
+        for (int i = 0; i < dksSize; i++) {
+            Long ks = deletableKeySets.valueAt(i);
             mKeySets.delete(ks);
             mKeySetMapping.delete(ks);
         }
-        for (Long keyId : deletableKeys) {
-            mPublicKeys.delete(keyId);
+        final int dkSize = deletableKeys.size();
+        for (int i = 0; i < dkSize; i++) {
+            mPublicKeys.delete(deletableKeys.valueAt(i));
         }
 
         // Now remove the deleted KeySets from each package's signingKeySets
         for (String pkgName : mPackages.keySet()) {
             PackageSetting p = mPackages.get(pkgName);
-            for (Long ks : deletableKeySets) {
+            for (int i = 0; i < dksSize; i++) {
+                Long ks = deletableKeySets.valueAt(i);
                 p.keySetData.removeSigningKeySet(ks);
             }
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2729392..e4f5e7d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -917,6 +917,7 @@
         writeBoolean(serializer, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
         writeBoolean(serializer, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
         writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
+        writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER);
         serializer.endTag(null, TAG_RESTRICTIONS);
     }
 
@@ -1063,6 +1064,7 @@
         readBoolean(parser, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
         readBoolean(parser, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
         readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
+        readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER);
     }
 
     private void readBoolean(XmlPullParser parser, Bundle restrictions,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9746142..62e7af4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -380,7 +380,6 @@
     boolean mHasSoftInput = false;
     boolean mTranslucentDecorEnabled = true;
     boolean mUseTvRouting;
-    boolean mUseMasterVolume;
 
     int mPointerLocationMode = 0; // guarded by mLock
 
@@ -540,6 +539,9 @@
     private boolean mAllowTheaterModeWakeFromLidSwitch;
     private boolean mAllowTheaterModeWakeFromWakeGesture;
 
+    // Whether to support long press from power button in non-interactive mode
+    private boolean mSupportLongPressPowerWhenNonInteractive;
+
     // Whether to go to sleep entering theater mode from power button
     private boolean mGoToSleepOnButtonPressTheaterMode;
 
@@ -886,12 +888,21 @@
                 }
             } else {
                 wakeUpFromPowerKey(event.getDownTime());
-                final int maxCount = getMaxMultiPressPowerCount();
 
-                if (maxCount <= 1) {
-                    mPowerKeyHandled = true;
-                } else {
+                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
+                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageDelayed(msg,
+                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                     mBeganFromNonInteractive = true;
+                } else {
+                    final int maxCount = getMaxMultiPressPowerCount();
+
+                    if (maxCount <= 1) {
+                        mPowerKeyHandled = true;
+                    } else {
+                        mBeganFromNonInteractive = true;
+                    }
                 }
             }
         }
@@ -1260,6 +1271,9 @@
         mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode);
 
+        mSupportLongPressPowerWhenNonInteractive = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_supportLongPressPowerWhenNonInteractive);
+
         mShortPressOnPowerBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shortPressOnPowerBehavior);
         mLongPressOnPowerBehavior = mContext.getResources().getInteger(
@@ -1270,8 +1284,6 @@
                 com.android.internal.R.integer.config_triplePressOnPowerBehavior);
 
         mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
-        mUseMasterVolume = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
 
         readConfigurationDependentBehaviors();
 
@@ -4859,26 +4871,16 @@
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
                 try {
-                    if (mUseMasterVolume) {
-                        getAudioService().adjustMasterVolume(AudioManager.ADJUST_RAISE, flags,
-                                pkgName);
-                    } else {
-                        getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
-                                AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
-                    }
+                    getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
+                            AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
                 }
                 break;
             case KeyEvent.KEYCODE_VOLUME_DOWN:
                 try {
-                    if (mUseMasterVolume) {
-                        getAudioService().adjustMasterVolume(AudioManager.ADJUST_LOWER, flags,
-                                pkgName);
-                    } else {
-                        getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
-                                AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
-                    }
+                    getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
+                            AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
                 }
@@ -4886,14 +4888,9 @@
             case KeyEvent.KEYCODE_VOLUME_MUTE:
                 try {
                     if (event.getRepeatCount() == 0) {
-                        if (mUseMasterVolume) {
-                            getAudioService().adjustMasterVolume(AudioManager.ADJUST_TOGGLE_MUTE,
-                                    flags, pkgName);
-                        } else {
-                            getAudioService().adjustSuggestedStreamVolume(
-                                    AudioManager.ADJUST_TOGGLE_MUTE,
-                                    AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
-                        }
+                        getAudioService().adjustSuggestedStreamVolume(
+                                AudioManager.ADJUST_TOGGLE_MUTE,
+                                AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
                     }
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index c3fc195..75c33af 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -5,6 +5,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -27,9 +28,6 @@
  * local or remote instances of keyguard.
  */
 public class KeyguardServiceDelegate {
-    public static final String KEYGUARD_PACKAGE = "com.android.systemui";
-    public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService";
-
     private static final String TAG = "KeyguardServiceDelegate";
     private static final boolean DEBUG = true;
 
@@ -111,10 +109,15 @@
 
     public void bindService(Context context) {
         Intent intent = new Intent();
-        intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
+        final Resources resources = context.getApplicationContext().getResources();
+
+        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
+                resources.getString(com.android.internal.R.string.config_keyguardComponent));
+        intent.setComponent(keyguardComponent);
+
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                 Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
-            Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+            Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
             mKeyguardState.showing = false;
             mKeyguardState.showingAndNotOccluded = false;
             mKeyguardState.secure = false;
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 772f831..0109313 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -398,6 +398,7 @@
     }
 
     public void destroy() {
+        mContext.unregisterReceiver(mBroadcastReceiver);
         mHandler.removeMessages(MSG_RESTART_TIMEOUT);
 
         if (!mBound) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index e57396f..ac8ad30 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -102,7 +102,6 @@
     };
     private int mCurrentIndex = 0;
     private int mCurrentMaxIndex = 0;
-    private final boolean mUseMasterVolume;
 
     // TODO: Should handle STANDBY case.
     private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
@@ -117,8 +116,6 @@
         mContext = context;
         mListener = listener;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        mUseMasterVolume = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
         mHal.init();
     }
 
@@ -139,12 +136,10 @@
             } else {
                 Slog.w(TAG, "HdmiControlService is not available");
             }
-            if (!mUseMasterVolume) {
-                final IntentFilter filter = new IntentFilter();
-                filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
-                filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
-                mContext.registerReceiver(mVolumeReceiver, filter);
-            }
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
+            filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+            mContext.registerReceiver(mVolumeReceiver, filter);
             updateVolume();
         }
     }
@@ -545,7 +540,7 @@
     }
 
     private float getMediaStreamVolume() {
-        return mUseMasterVolume ? 1.0f : ((float) mCurrentIndex / (float) mCurrentMaxIndex);
+        return (float) mCurrentIndex / (float) mCurrentMaxIndex;
     }
 
     private class Connection implements IBinder.DeathRecipient {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index b48fadb2..99cf8df 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -20,6 +20,7 @@
 
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.IUserSwitchObserver;
 import android.app.IWallpaperManager;
 import android.app.IWallpaperManagerCallback;
@@ -164,6 +165,7 @@
     final IWindowManager mIWindowManager;
     final IPackageManager mIPackageManager;
     final MyPackageMonitor mMonitor;
+    final AppOpsManager mAppOpsManager;
     WallpaperData mLastWallpaper;
 
     /**
@@ -478,6 +480,7 @@
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
         mIPackageManager = AppGlobals.getPackageManager();
+        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mMonitor = new MyPackageMonitor();
         mMonitor.register(context, null, UserHandle.ALL, true);
         getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
@@ -613,8 +616,12 @@
         }
     }
 
-    public void clearWallpaper() {
+    public void clearWallpaper(String callingPackage) {
         if (DEBUG) Slog.v(TAG, "clearWallpaper");
+        checkPermission(android.Manifest.permission.SET_WALLPAPER);
+        if (!isWallpaperSupported(callingPackage)) {
+            return;
+        }
         synchronized (mLock) {
             clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
         }
@@ -622,6 +629,9 @@
 
     void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) {
         WallpaperData wallpaper = mWallpaperMap.get(userId);
+        if (wallpaper == null) {
+            return;
+        }
         File f = new File(getWallpaperDir(userId), WALLPAPER);
         if (f.exists()) {
             f.delete();
@@ -668,6 +678,10 @@
                 Binder.restoreCallingIdentity(ident);
             }
             for (UserInfo user: users) {
+                // ignore managed profiles
+                if (user.isManagedProfile()) {
+                    continue;
+                }
                 WallpaperData wd = mWallpaperMap.get(user.id);
                 if (wd == null) {
                     // User hasn't started yet, so load her settings to peek at the wallpaper
@@ -690,8 +704,12 @@
         return p;
     }
 
-    public void setDimensionHints(int width, int height) throws RemoteException {
+    public void setDimensionHints(int width, int height, String callingPackage)
+            throws RemoteException {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+        if (!isWallpaperSupported(callingPackage)) {
+            return;
+        }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
             WallpaperData wallpaper = mWallpaperMap.get(userId);
@@ -733,19 +751,30 @@
     public int getWidthHint() throws RemoteException {
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
-            return wallpaper.width;
+            if (wallpaper != null) {
+                return wallpaper.width;
+            } else {
+                return 0;
+            }
         }
     }
 
     public int getHeightHint() throws RemoteException {
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
-            return wallpaper.height;
+            if (wallpaper != null) {
+                return wallpaper.height;
+            } else {
+                return 0;
+            }
         }
     }
 
-    public void setDisplayPadding(Rect padding) {
+    public void setDisplayPadding(Rect padding, String callingPackage) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+        if (!isWallpaperSupported(callingPackage)) {
+            return;
+        }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
             WallpaperData wallpaper = mWallpaperMap.get(userId);
@@ -791,6 +820,9 @@
                 wallpaperUserId = UserHandle.getUserId(callingUid);
             }
             WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
+            if (wallpaper == null) {
+                return null;
+            }
             try {
                 if (outParams != null) {
                     outParams.putInt("width", wallpaper.width);
@@ -814,15 +846,18 @@
         int userId = UserHandle.getCallingUserId();
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(userId);
-            if (wallpaper.connection != null) {
+            if (wallpaper != null && wallpaper.connection != null) {
                 return wallpaper.connection.mInfo;
             }
             return null;
         }
     }
 
-    public ParcelFileDescriptor setWallpaper(String name) {
+    public ParcelFileDescriptor setWallpaper(String name, String callingPackage) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
+        if (!isWallpaperSupported(callingPackage)) {
+            return null;
+        }
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper");
             int userId = UserHandle.getCallingUserId();
@@ -868,6 +903,13 @@
         return null;
     }
 
+    public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
+        if (isWallpaperSupported(callingPackage)) {
+            setWallpaperComponent(name);
+        }
+    }
+
+    // ToDo: Remove this version of the function
     public void setWallpaperComponent(ComponentName name) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
         synchronized (mLock) {
@@ -1097,6 +1139,15 @@
         }
     }
 
+    /**
+     * Certain user types do not support wallpapers (e.g. managed profiles). The check is
+     * implemented through through the OP_WRITE_WALLPAPER AppOp.
+     */
+    public boolean isWallpaperSupported(String callingPackage) {
+        return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
+                callingPackage) == AppOpsManager.MODE_ALLOWED;
+    }
+
     private static JournaledFile makeJournaledFile(int userId) {
         final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1174,7 +1225,7 @@
 
     private void loadSettingsLocked(int userId) {
         if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
-        
+
         JournaledFile journal = makeJournaledFile(userId);
         FileInputStream stream = null;
         File file = journal.chooseForRead();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7e69e87..a4f3f23 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -496,7 +496,12 @@
     int mLastDisplayFreezeDuration = 0;
     Object mLastFinishedFreezeSource = null;
     boolean mWaitingForConfig = false;
-    boolean mWindowsFreezingScreen = false;
+
+    final static int WINDOWS_FREEZING_SCREENS_NONE = 0;
+    final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1;
+    final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2;
+    private int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+
     boolean mClientFreezingScreen = false;
     int mAppsFreezingScreen = 0;
     int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -4699,7 +4704,7 @@
                 if (mAppsFreezingScreen == 1) {
                     startFreezingDisplayLocked(false, 0, 0);
                     mH.removeMessages(H.APP_FREEZE_TIMEOUT);
-                    mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 5000);
+                    mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
                 }
             }
             final int N = wtoken.allAppWindows.size();
@@ -6415,7 +6420,7 @@
         mAltOrientation = altOrientation;
         mPolicy.setRotationLw(mRotation);
 
-        mWindowsFreezingScreen = true;
+        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
@@ -7784,6 +7789,7 @@
                     // TODO(multidisplay): Can non-default displays rotate?
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "Window freeze timeout expired.");
+                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
                         final WindowList windows = getDefaultWindowListLocked();
                         int i = windows.size();
                         while (i > 0) {
@@ -7851,6 +7857,7 @@
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
+                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
                         final int numStacks = mStackIdToStack.size();
                         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                             final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
@@ -8914,8 +8921,8 @@
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
             mInnerFields.mOrientationChangeComplete = false;
-            if (!mWindowsFreezingScreen) {
-                mWindowsFreezingScreen = true;
+            if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
+                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
                 // XXX should probably keep timeout from
                 // when we first froze the display.
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
@@ -9905,8 +9912,8 @@
                 "With display frozen, orientationChangeComplete="
                 + mInnerFields.mOrientationChangeComplete);
         if (mInnerFields.mOrientationChangeComplete) {
-            if (mWindowsFreezingScreen) {
-                mWindowsFreezingScreen = false;
+            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
                 mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
             }
@@ -10188,7 +10195,7 @@
         } else {
             mInnerFields.mOrientationChangeComplete = true;
             mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
-            if (mWindowsFreezingScreen) {
+            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                 doRequest = true;
             }
         }
@@ -10524,7 +10531,8 @@
             return;
         }
 
-        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
+        if (mWaitingForConfig || mAppsFreezingScreen > 0
+                || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
                 || mClientFreezingScreen) {
             if (DEBUG_ORIENTATION) Slog.d(TAG,
                 "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 57ed876..ea59d4b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -53,6 +53,7 @@
 
     private static final String DEVICE_OWNER_XML = "device_owner.xml";
     private static final String TAG_DEVICE_OWNER = "device-owner";
+    private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
     private static final String TAG_PROFILE_OWNER = "profile-owner";
     private static final String ATTR_NAME = "name";
     private static final String ATTR_PACKAGE = "package";
@@ -68,6 +69,9 @@
     // Internal state for the device owner package.
     private OwnerInfo mDeviceOwner;
 
+    // Internal state for the device initializer package.
+    private OwnerInfo mDeviceInitializer;
+
     // Internal state for the profile owner packages.
     private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
 
@@ -104,6 +108,15 @@
     }
 
     /**
+     * Creates an instance of the device owner object with the device initializer set.
+     */
+    static DeviceOwner createWithDeviceInitializer(String packageName, String ownerName) {
+        DeviceOwner owner = new DeviceOwner();
+        owner.mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+        return owner;
+    }
+
+    /**
      * Creates an instance of the device owner object with the profile owner set.
      */
     static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
@@ -128,6 +141,26 @@
         mDeviceOwner = null;
     }
 
+    String getDeviceInitializerPackageName() {
+        return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
+    }
+
+    String getDeviceInitializerName() {
+        return mDeviceInitializer != null ? mDeviceInitializer.name : null;
+    }
+
+    void setDeviceInitializer(String packageName, String ownerName) {
+        mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+    }
+
+    void clearDeviceInitializer() {
+        mDeviceInitializer = null;
+    }
+
+    boolean hasDeviceInitializer() {
+        return mDeviceInitializer != null;
+    }
+
     void setProfileOwner(ComponentName admin, String ownerName, int userId) {
         mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
     }
@@ -199,6 +232,10 @@
                     String name = parser.getAttributeValue(null, ATTR_NAME);
                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     mDeviceOwner = new OwnerInfo(name, packageName);
+                } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
+                    String name = parser.getAttributeValue(null, ATTR_NAME);
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    mDeviceInitializer = new OwnerInfo(name, packageName);
                 } else if (tag.equals(TAG_PROFILE_OWNER)) {
                     String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -259,6 +296,16 @@
                 out.endTag(null, TAG_DEVICE_OWNER);
             }
 
+            // Write device initializer tag
+            if (mDeviceInitializer != null) {
+                out.startTag(null, TAG_DEVICE_INITIALIZER);
+                out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
+                if (mDeviceInitializer.name != null) {
+                    out.attribute(null, ATTR_NAME, mDeviceInitializer.name);
+                }
+                out.endTag(null, TAG_DEVICE_INITIALIZER);
+            }
+
             // Write profile owner tags
             if (mProfileOwners.size() > 0) {
                 for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a19cd9f..00d7971 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -51,6 +51,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
+import android.graphics.Bitmap;
 import android.hardware.usb.UsbManager;
 import android.media.AudioManager;
 import android.media.IAudioService;
@@ -179,6 +180,14 @@
         DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS);
     }
 
+    // The following user restrictions cannot be changed by any active admin, including device
+    // owner and profile owner.
+    private static final Set<String> IMMUTABLE_USER_RESTRICTIONS;
+    static {
+        IMMUTABLE_USER_RESTRICTIONS = new HashSet();
+        IMMUTABLE_USER_RESTRICTIONS.add(UserManager.DISALLOW_WALLPAPER);
+    }
+
     private static final Set<String> SECURE_SETTINGS_WHITELIST;
     private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST;
     private static final Set<String> GLOBAL_SETTINGS_WHITELIST;
@@ -1139,13 +1148,15 @@
             boolean ownsProfile = (getProfileOwner(userHandle) != null
                     && getProfileOwner(userHandle).getPackageName()
                         .equals(admin.info.getPackageName()));
+            boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
+                    && !hasUserSetupCompleted(userHandle);
 
             if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
-                if (ownsDevice) {
+                if (ownsDevice || (userHandle == UserHandle.USER_OWNER && ownsInitialization)) {
                     return admin;
                 }
             } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
-                if (ownsDevice || ownsProfile) {
+                if (ownsDevice || ownsProfile || ownsInitialization) {
                     return admin;
                 }
             } else {
@@ -1899,7 +1910,7 @@
                 return;
             }
             if (admin.getUid() != Binder.getCallingUid()) {
-                // If trying to remove device owner, refuse when the caller is not the owner.
+                // Active device owners must remain active admins.
                 if (isDeviceOwner(adminReceiver.getPackageName())) {
                     return;
                 }
@@ -3866,6 +3877,110 @@
     }
 
     @Override
+    public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
+            String ownerName) {
+        if (!mHasFeature) {
+            return false;
+        }
+        if (initializer == null || !DeviceOwner.isInstalled(
+                initializer.getPackageName(), mContext.getPackageManager())) {
+            throw new IllegalArgumentException("Invalid component name " + initializer
+                    + " for device initializer");
+        }
+        synchronized (this) {
+            enforceCanSetDeviceInitializer(who);
+
+            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+                throw new IllegalStateException(
+                        "Trying to set device initializer but device initializer is already set.");
+            }
+
+            if (mDeviceOwner == null) {
+                // Device owner state does not exist, create it.
+                mDeviceOwner = DeviceOwner.createWithDeviceInitializer(
+                        initializer.getPackageName(), ownerName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            } else {
+                // Device owner already exists, update it.
+                mDeviceOwner.setDeviceInitializer(initializer.getPackageName(), ownerName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            }
+        }
+    }
+
+    private void enforceCanSetDeviceInitializer(ComponentName who) {
+        if (who == null) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
+            if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+                throw new IllegalStateException(
+                        "Trying to set device initializer but device is already provisioned.");
+            }
+        } else {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+    }
+
+    @Override
+    public boolean isDeviceInitializer(String packageName) {
+        if (!mHasFeature) {
+            return false;
+        }
+        synchronized (this) {
+            return mDeviceOwner != null
+                    && mDeviceOwner.hasDeviceInitializer()
+                    && mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
+        }
+    }
+
+    @Override
+    public String getDeviceInitializer() {
+        if (!mHasFeature) {
+            return null;
+        }
+        synchronized (this) {
+            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+                return mDeviceOwner.getDeviceInitializerPackageName();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void clearDeviceInitializer(ComponentName who) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+
+        ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId());
+
+        if (admin.getUid() != Binder.getCallingUid()) {
+            throw new SecurityException("Admin " + who + " is not owned by uid "
+                    + Binder.getCallingUid());
+        }
+
+        if (!isDeviceInitializer(admin.info.getPackageName())
+                && !isDeviceOwner(admin.info.getPackageName())) {
+            throw new SecurityException(
+                    "clearDeviceInitializer can only be called by the device initializer/owner");
+        }
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                if (mDeviceOwner != null) {
+                    mDeviceOwner.clearDeviceInitializer();
+                    mDeviceOwner.writeOwnerFile();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
     public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
         if (!mHasFeature) {
             return false;
@@ -3938,7 +4053,7 @@
         Bundle userRestrictions = mUserManager.getUserRestrictions();
         mUserManager.setUserRestrictions(new Bundle(), userHandle);
         if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
-            audioManager.adjustMasterVolume(AudioManager.ADJUST_UNMUTE, 0);
+            audioManager.setMasterMute(false, 0);
         }
         if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
             audioManager.setMicrophoneMute(false);
@@ -3960,6 +4075,51 @@
     }
 
     @Override
+    public boolean setUserEnabled(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            int userId = UserHandle.getCallingUserId();
+
+            ActiveAdmin activeAdmin =
+                    getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (!isDeviceInitializer(activeAdmin.info.getPackageName())) {
+                throw new SecurityException(
+                        "This method can only be called by device initializers");
+            }
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
+                    IPackageManager ipm = AppGlobals.getPackageManager();
+                    ipm.setComponentEnabledSetting(who,
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                            PackageManager.DONT_KILL_APP, userId);
+
+                    removeActiveAdmin(who, userId);
+                }
+
+                if (userId == UserHandle.USER_OWNER) {
+                    Settings.Global.putInt(mContext.getContentResolver(),
+                            Settings.Global.DEVICE_PROVISIONED, 1);
+                }
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.USER_SETUP_COMPLETE, 1, userId);
+            } catch (RemoteException e) {
+                Log.i(LOG_TAG, "Can't talk to package manager", e);
+                return false;
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return true;
+        }
+    }
+
+    @Override
     public void setProfileEnabled(ComponentName who) {
         if (!mHasFeature) {
             return;
@@ -4801,6 +4961,9 @@
                     && 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);
 
             IAudioService iAudioService = null;
@@ -4815,8 +4978,7 @@
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
                         iAudioService.setMicrophoneMute(true, who.getPackageName());
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.adjustMasterVolume(AudioManager.ADJUST_MUTE, 0,
-                                who.getPackageName());
+                        iAudioService.setMasterMute(true, 0, who.getPackageName());
                     }
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -4881,8 +5043,7 @@
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
                         iAudioService.setMicrophoneMute(false, who.getPackageName());
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.adjustMasterVolume(AudioManager.ADJUST_UNMUTE, 0,
-                                who.getPackageName());
+                        iAudioService.setMasterMute(false, 0, who.getPackageName());
                     }
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -5322,10 +5483,8 @@
 
             IAudioService iAudioService = IAudioService.Stub.asInterface(
                     ServiceManager.getService(Context.AUDIO_SERVICE));
-            try{
-                iAudioService.adjustMasterVolume(
-                        on ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE, 0,
-                        who.getPackageName());
+            try {
+                iAudioService.setMasterMute(on, 0, who.getPackageName());
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Failed to setMasterMute", re);
             }
@@ -5344,6 +5503,22 @@
         }
     }
 
+    @Override
+    public void setUserIcon(ComponentName who, Bitmap icon) {
+        synchronized (this) {
+            Preconditions.checkNotNull(who, "ComponentName is null");
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            int userId = UserHandle.getCallingUserId();
+            long id = Binder.clearCallingIdentity();
+            try {
+                mUserManager.setUserIcon(userId, icon);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
     /**
      * We need to update the internal state of whether a user has completed setup once. After
      * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd6e786..a0c7f86 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -669,7 +669,8 @@
 
                 mSystemServiceManager.startService("com.android.server.wifi.RttService");
 
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET)) {
+                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
+                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
                     mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
                 }
 
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 3f180e7..b0e30b5 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -73,8 +73,6 @@
 
     private UsbAudioDevice mAccessoryAudioDevice = null;
 
-    private UsbAudioDevice mSelectedAudioDevice = null;
-
     // UsbMidiDevice for USB peripheral mode (gadget) device
     private UsbMidiDevice mPeripheralMidiDevice = null;
 
@@ -186,6 +184,10 @@
                 int device = (audioDevice == mAccessoryAudioDevice ?
                         AudioSystem.DEVICE_OUT_USB_ACCESSORY :
                         AudioSystem.DEVICE_OUT_USB_DEVICE);
+                if (DEBUG) {
+                    Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
+                            " addr:" + address + " name:" + audioDevice.mDeviceName);
+                }
                 mAudioService.setWiredDeviceConnectionState(
                         device, state, address, audioDevice.mDeviceName);
             }
@@ -282,23 +284,13 @@
     /*
      * Select the default device of the specified card.
      */
-    /* package */ boolean selectAudioCard(int card) {
+    /* package */ UsbAudioDevice selectAudioCard(int card) {
         if (DEBUG) {
             Slog.d(TAG, "selectAudioCard() card:" + card);
         }
         if (!mCardsParser.isCardUsb(card)) {
             // Don't. AudioPolicyManager has logic for falling back to internal devices.
-            return false;
-        }
-
-        if (mSelectedAudioDevice != null) {
-            if (mSelectedAudioDevice.mCard == card) {
-                // Nothing to do here.
-                return false;
-            }
-            // "disconnect" the AudioPolicyManager from the previously selected device.
-            notifyDeviceState(mSelectedAudioDevice, false);
-            mSelectedAudioDevice = null;
+            return null;
         }
 
         mDevicesParser.scan();
@@ -314,30 +306,30 @@
 
         // Playback device file needed/present?
         if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) {
-            return false;
+            return null;
         }
 
         // Capture device file needed/present?
         if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) {
-            return false;
+            return null;
         }
 
         if (DEBUG) {
             Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
         }
 
-        mSelectedAudioDevice =
+        UsbAudioDevice audioDevice =
                 new UsbAudioDevice(card, device, hasPlayback, hasCapture, deviceClass);
-        mSelectedAudioDevice.mDeviceName = mCardsParser.getCardRecordFor(card).mCardName;
-        mSelectedAudioDevice.mDeviceDescription =
-                mCardsParser.getCardRecordFor(card).mCardDescription;
+        AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card);
+        audioDevice.mDeviceName = cardRecord.mCardName;
+        audioDevice.mDeviceDescription = cardRecord.mCardDescription;
 
-        notifyDeviceState(mSelectedAudioDevice, true);
+        notifyDeviceState(audioDevice, true);
 
-        return true;
+        return audioDevice;
     }
 
-    /* package */ boolean selectDefaultDevice() {
+    /* package */ UsbAudioDevice selectDefaultDevice() {
         if (DEBUG) {
             Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()");
         }
@@ -347,7 +339,8 @@
 
     /* package */ void usbDeviceAdded(UsbDevice usbDevice) {
        if (DEBUG) {
-          Slog.d(TAG, "usbDeviceAdded(): " + usbDevice);
+          Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() +
+                  "nm:" + usbDevice.getProductName());
         }
 
         // Is there an audio interface in there?
@@ -384,8 +377,10 @@
         // If the default isn't a USB device, let the existing "select internal mechanism"
         // handle the selection.
         if (mCardsParser.isCardUsb(addedCard)) {
-            selectAudioCard(addedCard);
-            mAudioDevices.put(usbDevice, mSelectedAudioDevice);
+            UsbAudioDevice audioDevice = selectAudioCard(addedCard);
+            if (audioDevice != null) {
+                mAudioDevices.put(usbDevice, audioDevice);
+            }
 
             // look for MIDI devices
 
@@ -420,14 +415,14 @@
 
     /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
         if (DEBUG) {
-          Slog.d(TAG, "deviceRemoved(): " + usbDevice);
+          Slog.d(TAG, "deviceRemoved(): " + usbDevice.getManufacturerName() +
+                  " " + usbDevice.getProductName());
         }
 
         UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
         if (audioDevice != null) {
             if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
                 notifyDeviceState(audioDevice, false);
-                mSelectedAudioDevice = null;
 
                 // if there any external devices left, select one of them
                 selectDefaultDevice();
diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index b3900b9..8849acd 100644
--- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -96,7 +96,7 @@
                 }
                 try {
                     listenToSocket();
-                } catch (IOException e) {
+                } catch (Exception e) {
                     /* Don't loop too fast if adbd dies, before init restarts it */
                     SystemClock.sleep(1000);
                 }
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index e17abc0..51d61bb 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -19,8 +19,8 @@
 import android.content.Context;
 import android.media.midi.MidiDeviceInfo;
 import android.media.midi.MidiDeviceServer;
+import android.media.midi.MidiDispatcher;
 import android.media.midi.MidiManager;
-import android.media.midi.MidiPort;
 import android.media.midi.MidiReceiver;
 import android.media.midi.MidiSender;
 import android.os.Bundle;
@@ -30,6 +30,8 @@
 import android.system.StructPollfd;
 import android.util.Log;
 
+import libcore.io.IoUtils;
+
 import java.io.Closeable;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -39,8 +41,11 @@
 public final class UsbMidiDevice implements Closeable {
     private static final String TAG = "UsbMidiDevice";
 
-    private final MidiDeviceServer mServer;
-    private final MidiReceiver[] mOutputPortReceivers;
+    private MidiDeviceServer mServer;
+
+    private final MidiReceiver[] mInputPortReceivers;
+
+    private static final int BUFFER_SIZE = 512;
 
     // for polling multiple FileDescriptors for MIDI events
     private final StructPollfd[] mPollFDs;
@@ -50,12 +55,6 @@
     private final FileOutputStream[] mOutputStreams;
 
     public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
-        MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
-        if (midiManager == null) {
-            Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
-            return null;
-        }
-
         // FIXME - support devices with different number of input and output ports
         int subDevices = nativeGetSubdeviceCount(card, device);
         if (subDevices <= 0) {
@@ -70,19 +69,16 @@
             return null;
         }
 
-        MidiDeviceServer server = midiManager.createDeviceServer(subDevices, subDevices, properties,
-                false, MidiDeviceInfo.TYPE_USB);
-        if (server == null) {
+        UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors, fileDescriptors);
+        if (!midiDevice.register(context, properties)) {
+            IoUtils.closeQuietly(midiDevice);
             Log.e(TAG, "createDeviceServer failed");
             return null;
         }
-
-        return new UsbMidiDevice(server, fileDescriptors, fileDescriptors);
+        return midiDevice;
     }
 
-    private UsbMidiDevice(MidiDeviceServer server, FileDescriptor[] inputFiles,
-            FileDescriptor[] outputFiles) {
-        mServer = server;
+    private UsbMidiDevice(FileDescriptor[] inputFiles, FileDescriptor[] outputFiles) {
         int inputCount = inputFiles.length;
         int outputCount = outputFiles.length;
 
@@ -102,30 +98,40 @@
             mOutputStreams[i] = new FileOutputStream(outputFiles[i]);
         }
 
-        mOutputPortReceivers = new MidiReceiver[outputCount];
-        for (int port = 0; port < outputCount; port++) {
-            mOutputPortReceivers[port] = server.openOutputPortReceiver(port);
-        }
-
+        mInputPortReceivers = new MidiReceiver[inputCount];
         for (int port = 0; port < inputCount; port++) {
-            final int portNumberF = port;
-            MidiReceiver receiver = new MidiReceiver() {
-
+            final int portF = port;
+            mInputPortReceivers[port] = new MidiReceiver() {
                 @Override
-                public void post(byte[] data, int offset, int count, long timestamp)
+                public void receive(byte[] data, int offset, int count, long timestamp)
                         throws IOException {
                     // FIXME - timestamps are ignored, future posting not supported yet.
-                    mOutputStreams[portNumberF].write(data, offset, count);
+                    mOutputStreams[portF].write(data, offset, count);
                 }
             };
-            MidiSender sender = server.openInputPortSender(port);
-            sender.connect(receiver);
+        }
+    }
+
+    private boolean register(Context context, Bundle properties) {
+        MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
+        if (midiManager == null) {
+            Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
+            return false;
         }
 
+        int outputCount = mOutputStreams.length;
+        mServer = midiManager.createDeviceServer(mInputPortReceivers, outputCount,
+                properties, MidiDeviceInfo.TYPE_USB);
+        if (mServer == null) {
+            return false;
+        }
+        final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers();
+
+        // FIXME can we only run this when we have a dispatcher that has listeners?
         new Thread() {
             @Override
             public void run() {
-                byte[] buffer = new byte[MidiPort.MAX_PACKET_DATA_SIZE];
+                byte[] buffer = new byte[BUFFER_SIZE];
                 try {
                     boolean done = false;
                     while (!done) {
@@ -137,8 +143,8 @@
                                 pfd.revents = 0;
 
                                 int count = mInputStreams[index].read(buffer);
-                                mOutputPortReceivers[index].post(buffer, 0, count,
-                                        System.nanoTime());
+                                long timestamp = System.nanoTime();
+                                outputReceivers[index].receive(buffer, 0, count, timestamp);
                             } else if ((pfd.revents & (OsConstants.POLLERR
                                                         | OsConstants.POLLHUP)) != 0) {
                                 done = true;
@@ -155,11 +161,15 @@
                 }
             }
         }.start();
+
+        return true;
     }
 
     @Override
     public void close() throws IOException {
-        mServer.close();
+        if (mServer != null) {
+            mServer.close();
+        }
 
         for (int i = 0; i < mInputStreams.length; i++) {
             mInputStreams[i].close();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0a4b787..f3b2d2e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3716,6 +3716,34 @@
     }
 
     /**
+     * Whether the device supports configuring the DTMF tone length.
+     *
+     * @return {@code true} if the DTMF tone length can be changed, and {@code false} otherwise.
+     */
+    public boolean canChangeDtmfToneLength() {
+        try {
+            return getITelephony().canChangeDtmfToneLength();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
+        }
+        return false;
+    }
+
+    /**
+     * Whether the device is a world phone.
+     *
+     * @return {@code true} if the device is a world phone, and {@code false} otherwise.
+     */
+    public boolean isWorldPhone() {
+        try {
+            return getITelephony().isWorldPhone();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
+        }
+        return false;
+    }
+
+    /**
      * This function retrieves value for setting "name+subId", and if that is not found
      * retrieves value for setting "name", and if that is not found uses def as default
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62c8746..3769dee 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -863,11 +863,25 @@
     /**
      * Whether video calling has been enabled by the user.
      *
-     * @return {@code True} if the user has enabled video calling, {@code false} otherwise.
+     * @return {@code true} if the user has enabled video calling, {@code false} otherwise.
      */
     boolean isVideoCallingEnabled();
 
     /**
+     * Whether the DTMF tone length can be changed.
+     *
+     * @return {@code true} if the DTMF tone length can be changed.
+     */
+    boolean canChangeDtmfToneLength();
+
+    /**
+     * Whether the device is a world phone.
+     *
+     * @return {@code true} if the devices is a world phone.
+     */
+    boolean isWorldPhone();
+
+    /**
      * Get IMS Registration Status
      */
     boolean isImsRegistered();
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 3d763c7..3c4da9e 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -107,7 +107,7 @@
     }
 
     /**
-     * @param context : the context that will be delagated.
+     * @param context : the context that will be delegated.
      * @param filePrefix : a prefix with which database and file names will be
      * prefixed.
      */
@@ -118,8 +118,8 @@
     }
 
     /**
-     * @param context : the context that will be delagated.
-     * @param fileContext : the context that file and db methods will be delgated to
+     * @param context : the context that will be delegated.
+     * @param fileContext : the context that file and db methods will be delegated to
      * @param filePrefix : a prefix with which database and file names will be
      * prefixed.
      */
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 5ab177b..063b4e6 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -481,8 +481,9 @@
 
     // assuming the image is a round rect, compute the radius by marching
     // diagonally from the top left corner towards the center
-    image->outlineAlpha = max(max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
-            max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
+    image->outlineAlpha = std::max(
+        max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
+        max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
 
     int diagonalInset = 0;
     find_max_opacity(image->rows, innerStartX, innerStartY, innerMidX, innerMidY, 1, 1,
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 6fbc17c..941a288 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1807,7 +1807,7 @@
         }
 
         const ResTable& featureTable = featureAssetManager.getResources(false);
-        mTypeIdOffset = max(mTypeIdOffset,
+        mTypeIdOffset = std::max(mTypeIdOffset,
                 findLargestTypeIdForPackage(featureTable, mAssetsPackage)); 
     }
 
@@ -2703,20 +2703,16 @@
     const String8 defaultLocale;
 
     // For all strings...
-    for (map<String16, map<String8, SourcePos> >::iterator nameIter = mLocalizations.begin();
-         nameIter != mLocalizations.end();
-         nameIter++) {
-        const map<String8, SourcePos>& configSrcMap = nameIter->second;
+    for (const auto& nameIter : mLocalizations) {
+        const std::map<String8, SourcePos>& configSrcMap = nameIter.second;
 
         // Look for strings with no default localization
         if (configSrcMap.count(defaultLocale) == 0) {
             SourcePos().warning("string '%s' has no default translation.",
-                    String8(nameIter->first).string());
+                    String8(nameIter.first).string());
             if (mBundle->getVerbose()) {
-                for (map<String8, SourcePos>::const_iterator locales = configSrcMap.begin();
-                    locales != configSrcMap.end();
-                    locales++) {
-                    locales->second.printf("locale %s found", locales->first.string());
+                for (const auto& locale : configSrcMap) {
+                    locale.second.printf("locale %s found", locale.first.string());
                 }
             }
             // !!! TODO: throw an error here in some circumstances
@@ -2727,8 +2723,8 @@
             const char* allConfigs = mBundle->getConfigurations().string();
             const char* start = allConfigs;
             const char* comma;
-            
-            set<String8> missingConfigs;
+
+            std::set<String8> missingConfigs;
             AaptLocaleValue locale;
             do {
                 String8 config;
@@ -2762,13 +2758,11 @@
 
             if (!missingConfigs.empty()) {
                 String8 configStr;
-                for (set<String8>::iterator iter = missingConfigs.begin();
-                     iter != missingConfigs.end();
-                     iter++) {
-                    configStr.appendFormat(" %s", iter->string());
+                for (const auto& iter : missingConfigs) {
+                    configStr.appendFormat(" %s", iter.string());
                 }
                 SourcePos().warning("string '%s' is missing %u required localizations:%s",
-                        String8(nameIter->first).string(),
+                        String8(nameIter.first).string(),
                         (unsigned int)missingConfigs.size(),
                         configStr.string());
             }
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index eef0ae1..9644224 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -17,8 +17,6 @@
 #include "StringPool.h"
 #include "Symbol.h"
 
-using namespace std;
-
 class XMLNode;
 class ResourceTable;
 
@@ -29,7 +27,7 @@
     XML_COMPILE_STRIP_WHITESPACE = 1<<3,
     XML_COMPILE_STRIP_RAW_VALUES = 1<<4,
     XML_COMPILE_UTF8 = 1<<5,
-    
+
     XML_COMPILE_STANDARD_RESOURCE =
             XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
             | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
@@ -116,7 +114,7 @@
      * and would mess up iteration order for the existing
      * resources.
      */
-    queue<CompileResourceWorkItem>& getWorkQueue() {
+    std::queue<CompileResourceWorkItem>& getWorkQueue() {
         return mWorkQueue;
     }
 
@@ -587,10 +585,10 @@
     size_t mNumLocal;
     SourcePos mCurrentXmlPos;
     Bundle* mBundle;
-    
+
     // key = string resource name, value = set of locales in which that name is defined
-    map<String16, map<String8, SourcePos> > mLocalizations;
-    queue<CompileResourceWorkItem> mWorkQueue;
+    std::map<String16, std::map<String8, SourcePos>> mLocalizations;
+    std::queue<CompileResourceWorkItem> mWorkQueue;
 };
 
 #endif
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 8d24d38..970b9d0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -76,13 +76,6 @@
     // ---- Public Helper methods ----
 
     /**
-     * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
-     */
-    public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
-        return sManager.getDelegate(bitmap.mNativeBitmap);
-    }
-
-    /**
      * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
      */
     public static Bitmap_Delegate getDelegate(long native_bitmap) {
@@ -187,19 +180,6 @@
         return createBitmap(delegate, createFlags, density.getDpiValue());
     }
 
-    /**
-     * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
-     */
-    public static BufferedImage getImage(Bitmap bitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
-        if (delegate == null) {
-            return null;
-        }
-
-        return delegate.mImage;
-    }
-
     public static int getBufferedImageType(int nativeBitmapConfig) {
         switch (Config.nativeToConfig(nativeBitmapConfig)) {
             case ALPHA_8:
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index 929d625..e24b3d5 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -1,6 +1,7 @@
 package android.text;
 
 import com.android.annotations.NonNull;
+import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.text.StaticLayout.LineBreaks;
@@ -27,14 +28,19 @@
     private static final char CHAR_NEWLINE   = 0x0A;
     private static final char CHAR_ZWSP      = 0x200B;  // Zero width space.
 
+    // ---- Builder delegate manager ----
+    private static final DelegateManager<Builder> sBuilderManager =
+        new DelegateManager<Builder>(Builder.class);
+
     @LayoutlibDelegate
-    /*package*/ static int nComputeLineBreaks(String locale, char[] inputText, float[] widths,
+    /*package*/ static int nComputeLineBreaks(long nativeBuilder, char[] inputText, float[] widths,
             int length, float firstWidth, int firstWidthLineCount, float restWidth,
             int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
             int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) {
 
+        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
         // compute all possible breakpoints.
-        BreakIterator it = BreakIterator.getLineInstance(new ULocale(locale));
+        BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
         it.setText(new Segment(inputText, 0, length));
         // average word length in english is 5. So, initialize the possible breaks with a guess.
         List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
@@ -97,4 +103,32 @@
                 PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY));
         return primitives;
     }
+
+    @LayoutlibDelegate
+    /*package*/ static long nNewBuilder() {
+        return sBuilderManager.addNewDelegate(new Builder());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nFinishBuilder(long nativeBuilder) {
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nFreeBuilder(long nativeBuilder) {
+        sBuilderManager.removeJavaReferenceFor(nativeBuilder);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nBuilderSetLocale(long nativeBuilder, String locale) {
+        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+        builder.mLocale = locale;
+    }
+
+    /**
+     * Java representation of the native Builder class. It currently only stores the locale
+     * set by nBuilderSetLocale.
+     */
+    static class Builder {
+        String mLocale;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
index 38846bd..a0db7bf 100644
--- a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
@@ -65,6 +65,9 @@
     @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"})  // Imported code
     public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
             float shadowOpacity, int shadowRgb) {
+        if (shadowSize == 0) {
+            return source;
+        }
 
         // This code is based on
         //      http://www.jroller.com/gfx/entry/non_rectangular_shadow
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 4d2c2fc..c6d60f8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -181,7 +181,7 @@
      */
     private static LayoutLog sCurrentLog = sDefaultLog;
 
-    private static final int LAST_SUPPORTED_FEATURE = Features.PREFERENCES_RENDERING;
+    private static final int LAST_SUPPORTED_FEATURE = Features.RENDER_ALL_DRAWABLE_STATES;
 
     @Override
     public int getApiLevel() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
new file mode 100644
index 0000000..cfc8f40
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -0,0 +1,39 @@
+/*
+ * 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.layoutlib.bridge.android;
+
+import com.android.ide.common.rendering.api.SessionParams.Key;
+
+/**
+ * This contains all known keys for the {@link RenderParams#getFlag(Key)}.
+ * <p/>
+ * The IDE has its own copy of this class which may be newer or older than this one.
+ * <p/>
+ * Constants should never be modified or removed from this class.
+ */
+public final class RenderParamsFlags {
+
+    public static final Key<String> FLAG_KEY_ROOT_TAG =
+            new Key<String>("rootTag", String.class);
+    public static final Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
+            new Key<Boolean>("disableBitmapCaching", Boolean.class);
+    public static final Key<Boolean> FLAG_KEY_RENDER_ALL_DRAWABLE_STATES =
+            new Key<Boolean>("renderAllDrawableStates", Boolean.class);
+
+    // Disallow instances.
+    private RenderParamsFlags() {}
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
deleted file mode 100644
index 51a0104..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
+++ /dev/null
@@ -1,37 +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.layoutlib.bridge.android;
-
-import com.android.ide.common.rendering.api.SessionParams;
-
-/**
- * This contains all known keys for the {@link SessionParams#getFlag(SessionParams.Key)}.
- * <p/>
- * The IDE has its own copy of this class which may be newer or older than this one.
- * <p/>
- * Constants should never be modified or removed from this class.
- */
-public final class SessionParamsFlags {
-
-    public static final SessionParams.Key<String> FLAG_KEY_ROOT_TAG =
-            new SessionParams.Key<String>("rootTag", String.class);
-    public static final SessionParams.Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
-            new SessionParams.Key<Boolean>("disableBitmapCaching", Boolean.class);
-
-    // Disallow instances.
-    private SessionParamsFlags() {}
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 669e6b5..3dee1e2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -16,20 +16,20 @@
 
 package com.android.layoutlib.bridge.impl;
 
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
-
 import com.android.ide.common.rendering.api.DrawableParams;
 import com.android.ide.common.rendering.api.HardwareConfig;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.Result.Status;
 import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 import com.android.resources.ResourceType;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
 import android.view.AttachInfo_Accessor;
 import android.view.View.MeasureSpec;
 import android.widget.FrameLayout;
@@ -38,7 +38,9 @@
 import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
@@ -71,11 +73,37 @@
             return Status.ERROR_NOT_A_DRAWABLE.createResult();
         }
 
+        Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+
+        final Boolean allStates =
+                params.getFlag(RenderParamsFlags.FLAG_KEY_RENDER_ALL_DRAWABLE_STATES);
+        if (allStates == Boolean.TRUE) {
+            final List<BufferedImage> result;
+
+            if (d instanceof StateListDrawable) {
+                result = new ArrayList<BufferedImage>();
+                final StateListDrawable stateList = (StateListDrawable) d;
+                for (int i = 0; i < stateList.getStateCount(); i++) {
+                    final Drawable stateDrawable = stateList.getStateDrawable(i);
+                    result.add(renderImage(hardwareConfig, stateDrawable, context));
+                }
+            } else {
+                result = Collections.singletonList(renderImage(hardwareConfig, d, context));
+            }
+
+            return Status.SUCCESS.createResult(result);
+        } else {
+            BufferedImage image = renderImage(hardwareConfig, d, context);
+            return Status.SUCCESS.createResult(image);
+        }
+    }
+
+    private BufferedImage renderImage(HardwareConfig hardwareConfig, Drawable d,
+            BridgeContext context) {
         // create a simple FrameLayout
         FrameLayout content = new FrameLayout(context);
 
         // get the actual Drawable object to draw
-        Drawable d = ResourceHelper.getDrawable(drawableResource, context);
         content.setBackground(d);
 
         // set the AttachInfo on the root view.
@@ -83,8 +111,27 @@
 
 
         // measure
-        int w = hardwareConfig.getScreenWidth();
-        int h = hardwareConfig.getScreenHeight();
+        int w = d.getIntrinsicWidth();
+        int h = d.getIntrinsicHeight();
+
+        final int screenWidth = hardwareConfig.getScreenWidth();
+        final int screenHeight = hardwareConfig.getScreenHeight();
+
+        if (w == -1 || h == -1) {
+            // Use screen size when either intrinsic width or height isn't available
+            w = screenWidth;
+            h = screenHeight;
+        } else if (w > screenWidth || h > screenHeight) {
+            // If image wouldn't fit to the screen, resize it to avoid cropping.
+
+            // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight
+            double scale = Math.min((double) screenWidth / w, (double) screenHeight / h);
+
+            // scale * w / scale * h = w / h, so, proportions are preserved.
+            w = (int) Math.floor(scale * w);
+            h = (int) Math.floor(scale * h);
+        }
+
         int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
         int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
         content.measure(w_spec, h_spec);
@@ -108,8 +155,7 @@
 
         // and draw
         content.draw(canvas);
-
-        return Status.SUCCESS.createResult(image);
+        return image;
     }
 
     protected BufferedImage getImage(int w, int h) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 875cc87..607563a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -50,7 +50,7 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 import com.android.layoutlib.bridge.bars.BridgeActionBar;
 import com.android.layoutlib.bridge.bars.AppCompatActionBar;
 import com.android.layoutlib.bridge.bars.Config;
@@ -400,7 +400,7 @@
             // it can instantiate the custom Fragment.
             Fragment_Delegate.setProjectCallback(params.getProjectCallback());
 
-            String rootTag = params.getFlag(SessionParamsFlags.FLAG_KEY_ROOT_TAG);
+            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
             boolean isPreference = "PreferenceScreen".equals(rootTag);
             View view;
             if (isPreference) {
@@ -557,7 +557,7 @@
                 // This is useful when mImage is just a wrapper of Graphics2D so
                 // it doesn't get cached.
                 boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
-                    SessionParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
+                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
                 if (newRenderSize || mCanvas == null || disableBitmapCaching) {
                     if (params.getImageFactory() != null) {
                         mImage = params.getImageFactory().getImage(
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 533b8bc..6263463 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -21,37 +21,37 @@
 
 /**
  * Record of energy and activity information from controller and
- * underlying wifi stack state.Timestamp the record with system
- * time
+ * underlying wifi stack state. Timestamp the record with elapsed
+ * real-time.
  * @hide
  */
 public final class WifiActivityEnergyInfo implements Parcelable {
+    private final long mTimestamp;
     private final int mStackState;
     private final int mControllerTxTimeMs;
     private final int mControllerRxTimeMs;
     private final int mControllerIdleTimeMs;
     private final int mControllerEnergyUsed;
-    private final long timestamp;
 
     public static final int STACK_STATE_INVALID = 0;
     public static final int STACK_STATE_STATE_ACTIVE = 1;
     public static final int STACK_STATE_STATE_SCANNING = 2;
     public static final int STACK_STATE_STATE_IDLE = 3;
 
-    public WifiActivityEnergyInfo(int stackState, int txTime, int rxTime,
-                                  int idleTime, int energyUsed) {
+    public WifiActivityEnergyInfo(long timestamp, int stackState,
+                                  int txTime, int rxTime, int idleTime, int energyUsed) {
+        mTimestamp = timestamp;
         mStackState = stackState;
         mControllerTxTimeMs = txTime;
         mControllerRxTimeMs = rxTime;
         mControllerIdleTimeMs = idleTime;
         mControllerEnergyUsed = energyUsed;
-        timestamp = System.currentTimeMillis();
     }
 
     @Override
     public String toString() {
         return "WifiActivityEnergyInfo{"
-            + " timestamp=" + timestamp
+            + " timestamp=" + mTimestamp
             + " mStackState=" + mStackState
             + " mControllerTxTimeMs=" + mControllerTxTimeMs
             + " mControllerRxTimeMs=" + mControllerRxTimeMs
@@ -63,13 +63,14 @@
     public static final Parcelable.Creator<WifiActivityEnergyInfo> CREATOR =
             new Parcelable.Creator<WifiActivityEnergyInfo>() {
         public WifiActivityEnergyInfo createFromParcel(Parcel in) {
+            long timestamp = in.readLong();
             int stackState = in.readInt();
             int txTime = in.readInt();
             int rxTime = in.readInt();
             int idleTime = in.readInt();
             int energyUsed = in.readInt();
-            return new WifiActivityEnergyInfo(stackState, txTime, rxTime,
-                    idleTime, energyUsed);
+            return new WifiActivityEnergyInfo(timestamp, stackState,
+                    txTime, rxTime, idleTime, energyUsed);
         }
         public WifiActivityEnergyInfo[] newArray(int size) {
             return new WifiActivityEnergyInfo[size];
@@ -77,6 +78,7 @@
     };
 
     public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mTimestamp);
         out.writeInt(mStackState);
         out.writeInt(mControllerTxTimeMs);
         out.writeInt(mControllerRxTimeMs);
@@ -127,7 +129,7 @@
      * @return timestamp(wall clock) of record creation
      */
     public long getTimeStamp() {
-        return timestamp;
+        return mTimestamp;
     }
 
     /**