Merge "introduce WifiConnectionstatistics" into lmp-dev
diff --git a/Android.mk b/Android.mk
index 7dfa6a0..4376ed6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -131,7 +131,7 @@
 	core/java/android/content/pm/IPackageInstallObserver.aidl \
 	core/java/android/content/pm/IPackageInstallObserver2.aidl \
 	core/java/android/content/pm/IPackageInstaller.aidl \
-	core/java/android/content/pm/IPackageInstallerObserver.aidl \
+	core/java/android/content/pm/IPackageInstallerCallback.aidl \
 	core/java/android/content/pm/IPackageInstallerSession.aidl \
 	core/java/android/content/pm/IPackageManager.aidl \
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
@@ -155,7 +155,7 @@
 	core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
 	core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
 	core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl \
-	core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl \
+	core/java/android/hardware/hdmi/IHdmiRecordListener.aidl \
 	core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl \
 	core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
@@ -215,7 +215,6 @@
 	core/java/android/print/IWriteResultCallback.aidl \
 	core/java/android/printservice/IPrintService.aidl \
 	core/java/android/printservice/IPrintServiceClient.aidl \
-	core/java/android/service/dreams/IDozeHardware.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \
@@ -297,6 +296,7 @@
 	location/java/android/location/IGeocodeProvider.aidl \
 	location/java/android/location/IGeofenceProvider.aidl \
 	location/java/android/location/IGpsMeasurementsListener.aidl \
+	location/java/android/location/IGpsNavigationMessageListener.aidl \
 	location/java/android/location/IGpsStatusListener.aidl \
 	location/java/android/location/IGpsStatusProvider.aidl \
 	location/java/android/location/ILocationListener.aidl \
@@ -348,8 +348,8 @@
 	media/java/android/media/tv/ITvInputServiceCallback.aidl \
 	media/java/android/media/tv/ITvInputSession.aidl \
 	media/java/android/media/tv/ITvInputSessionCallback.aidl \
-	telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl \
-	telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl \
+	telecomm/java/com/android/internal/telecomm/IVideoCallCallback.aidl \
+	telecomm/java/com/android/internal/telecomm/IVideoCallProvider.aidl \
 	telecomm/java/com/android/internal/telecomm/IConnectionService.aidl \
 	telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl \
 	telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 3014e0f..fff8a85 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -212,6 +212,8 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telecomm/java/com/android/internal/telecomm)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework.* $(PRODUCT_OUT)/system/framework2.*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/docs/api-stubs-timestamp)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index a49e0f7..8302bba 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -564,9 +564,9 @@
     field public static final int fastScrollTextColor = 16843609; // 0x1010359
     field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
     field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
-    field public static final int fill = 16843807; // 0x101041f
     field public static final int fillAfter = 16843197; // 0x10101bd
     field public static final int fillBefore = 16843196; // 0x10101bc
+    field public static final int fillColor = 16843807; // 0x101041f
     field public static final int fillEnabled = 16843343; // 0x101024f
     field public static final int fillOpacity = 16843806; // 0x101041e
     field public static final int fillViewport = 16843130; // 0x101017a
@@ -1064,10 +1064,6 @@
     field public static final int scrollingCache = 16843006; // 0x10100fe
     field public static final deprecated int searchButtonText = 16843269; // 0x1010205
     field public static final int searchIcon = 16843909; // 0x1010485
-    field public static final int searchKeyphrase = 16843873; // 0x1010461
-    field public static final int searchKeyphraseId = 16843872; // 0x1010460
-    field public static final int searchKeyphraseRecognitionFlags = 16843948; // 0x10104ac
-    field public static final int searchKeyphraseSupportedLocales = 16843874; // 0x1010462
     field public static final int searchMode = 16843221; // 0x10101d5
     field public static final int searchSettingsDescription = 16843402; // 0x101028a
     field public static final int searchSuggestAuthority = 16843222; // 0x10101d6
@@ -1165,7 +1161,7 @@
     field public static final int streamType = 16843273; // 0x1010209
     field public static final int stretchColumns = 16843081; // 0x1010149
     field public static final int stretchMode = 16843030; // 0x1010116
-    field public static final int stroke = 16843809; // 0x1010421
+    field public static final int strokeColor = 16843809; // 0x1010421
     field public static final int strokeLineCap = 16843815; // 0x1010427
     field public static final int strokeLineJoin = 16843816; // 0x1010428
     field public static final int strokeOpacity = 16843810; // 0x1010422
@@ -1392,6 +1388,7 @@
     field public static final int windowAllowExitTransitionOverlap = 16843837; // 0x101043d
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
+    field public static final int windowClipToOutline = 16843953; // 0x10104b1
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
     field public static final int windowContentOverlay = 16842841; // 0x1010059
     field public static final int windowContentTransitionManager = 16843795; // 0x1010413
@@ -3396,6 +3393,7 @@
     method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
     method protected void onDestroy();
     method public void onDetachedFromWindow();
+    method public void onEnterAnimationComplete();
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -3603,6 +3601,7 @@
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public int affiliatedTaskId;
     field public android.content.Intent baseIntent;
     field public java.lang.CharSequence description;
     field public int id;
@@ -5418,6 +5417,7 @@
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
     field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.defaultManagedProfileName";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.deviceAdminPackageChecksum";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.deviceAdminPackageDownloadCookieHeader";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.deviceAdminPackageDownloadLocation";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.ManagedProfileEmailAddress";
@@ -7597,6 +7597,7 @@
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
     field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
+    field public static final java.lang.String ACTION_CONFIRM_DEVICE_CREDENTIAL = "android.intent.action.CONFIRM_DEVICE_CREDENTIAL";
     field public static final java.lang.String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
     field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
     field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED";
@@ -7739,6 +7740,7 @@
     field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
     field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
     field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
+    field public static final java.lang.String EXTRA_DETAILS = "android.intent.extra.DETAILS";
     field public static final java.lang.String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
     field public static final int EXTRA_DOCK_STATE_CAR = 2; // 0x2
     field public static final int EXTRA_DOCK_STATE_DESK = 1; // 0x1
@@ -8457,32 +8459,31 @@
 
   public class InstallSessionInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public android.graphics.Bitmap getIcon();
+    method public android.graphics.Bitmap getAppIcon();
+    method public java.lang.CharSequence getAppLabel();
+    method public java.lang.String getAppPackageName();
     method public java.lang.String getInstallerPackageName();
-    method public java.lang.String getPackageName();
-    method public int getProgress();
+    method public float getProgress();
     method public int getSessionId();
-    method public java.lang.CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
   public class InstallSessionParams implements android.os.Parcelable {
-    ctor public InstallSessionParams();
+    ctor public InstallSessionParams(int);
     method public int describeContents();
-    method public void setDeltaSize(long);
-    method public void setIcon(android.graphics.Bitmap);
+    method public void setAppIcon(android.graphics.Bitmap);
+    method public void setAppLabel(java.lang.CharSequence);
+    method public void setAppPackageName(java.lang.String);
     method public void setInstallLocation(int);
-    method public void setModeFullInstall();
-    method public void setModeInheritExisting();
     method public void setOriginatingUri(android.net.Uri);
-    method public void setPackageName(java.lang.String);
-    method public void setProgressMax(int);
     method public void setReferrerUri(android.net.Uri);
     method public void setSignatures(android.content.pm.Signature[]);
-    method public void setTitle(java.lang.CharSequence);
+    method public void setSize(long);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int MODE_FULL_INSTALL = 1; // 0x1
+    field public static final int MODE_INHERIT_EXISTING = 2; // 0x2
   }
 
   public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -8535,6 +8536,7 @@
     method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle);
     method public void removeOnAppsChangedCallback(android.content.pm.LauncherApps.OnAppsChangedCallback);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
+    method public void showAppDetailsForProfile(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startActivityForProfile(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
   }
 
@@ -8582,42 +8584,47 @@
   }
 
   public class PackageInstaller {
+    method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
+    method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
     method public int createSession(android.content.pm.InstallSessionParams) throws java.io.IOException;
-    method public java.util.List<android.content.pm.InstallSessionInfo> getActiveSessions();
+    method public java.util.List<android.content.pm.InstallSessionInfo> getAllSessions();
+    method public java.util.List<android.content.pm.InstallSessionInfo> getMySessions();
+    method public android.content.pm.InstallSessionInfo getSessionInfo(int);
     method public android.content.pm.PackageInstaller.Session openSession(int);
-    method public void registerSessionObserver(android.content.pm.PackageInstaller.SessionObserver);
-    method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallResultCallback);
-    method public void unregisterSessionObserver(android.content.pm.PackageInstaller.SessionObserver);
+    method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
+    method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallCallback);
   }
 
-  public static abstract class PackageInstaller.CommitResultCallback {
-    ctor public PackageInstaller.CommitResultCallback();
-    method public abstract void onFailure(java.lang.String);
-    method public void onFailureConflict(java.lang.String, java.lang.String);
-    method public void onFailureIncompatible(java.lang.String);
-    method public void onFailureInvalid(java.lang.String);
-    method public void onFailureStorage(java.lang.String);
+  public static abstract class PackageInstaller.CommitCallback {
+    ctor public PackageInstaller.CommitCallback();
+    method public abstract void onFailure(int, java.lang.String, android.os.Bundle);
     method public abstract void onSuccess();
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+    field public static final int FAILURE_CONFLICT = 2; // 0x2
+    field public static final int FAILURE_INCOMPATIBLE = 4; // 0x4
+    field public static final int FAILURE_INVALID = 1; // 0x1
+    field public static final int FAILURE_STORAGE = 3; // 0x3
+    field public static final int FAILURE_UNKNOWN = 0; // 0x0
   }
 
   public static class PackageInstaller.Session implements java.io.Closeable {
+    method public void abandon();
     method public void close();
-    method public void commit(android.content.pm.PackageInstaller.CommitResultCallback);
-    method public void destroy();
+    method public void commit(android.content.pm.PackageInstaller.CommitCallback);
     method public void fsync(java.io.OutputStream) throws java.io.IOException;
     method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
-    method public void setProgress(int);
+    method public void setProgress(float);
   }
 
-  public static abstract class PackageInstaller.SessionObserver {
-    ctor public PackageInstaller.SessionObserver();
-    method public abstract void onCreated(android.content.pm.InstallSessionInfo);
-    method public abstract void onFinalized(int, boolean);
-    method public abstract void onProgress(int, int);
+  public static abstract class PackageInstaller.SessionCallback {
+    ctor public PackageInstaller.SessionCallback();
+    method public abstract void onCreated(int);
+    method public abstract void onFinished(int, boolean);
+    method public abstract void onProgressChanged(int, float);
   }
 
-  public static abstract class PackageInstaller.UninstallResultCallback {
-    ctor public PackageInstaller.UninstallResultCallback();
+  public static abstract class PackageInstaller.UninstallCallback {
+    ctor public PackageInstaller.UninstallCallback();
     method public abstract void onFailure(java.lang.String);
     method public abstract void onSuccess();
   }
@@ -8684,7 +8691,6 @@
     method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
-    method public abstract android.content.pm.PackageInstaller getInstaller();
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
@@ -8694,6 +8700,7 @@
     method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PackageInstaller getPackageInstaller();
     method public abstract java.lang.String[] getPackagesForUid(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -12650,7 +12657,6 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_TIMESTAMP_CALIBRATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_WHITE_LEVEL;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_MAX_ANALOG_SENSITIVITY;
-    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_NOISE_PROFILE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_ORIENTATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT1;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT2;
@@ -13024,6 +13030,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_FRAME_DURATION;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_GREEN_SPLIT;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NEUTRAL_COLOR_POINT;
+    field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NOISE_PROFILE;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_ROLLING_SHUTTER_SKEW;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_SENSITIVITY;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA;
@@ -14138,10 +14145,10 @@
     method public void loadSoundEffects();
     method public void playSoundEffect(int);
     method public void playSoundEffect(int, float);
-    method public void registerMediaButtonEventReceiver(android.content.ComponentName);
-    method public void registerMediaButtonEventReceiver(android.app.PendingIntent);
-    method public void registerRemoteControlClient(android.media.RemoteControlClient);
-    method public boolean registerRemoteController(android.media.RemoteController);
+    method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
+    method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
+    method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
+    method public deprecated boolean registerRemoteController(android.media.RemoteController);
     method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
     method public deprecated void setBluetoothA2dpOn(boolean);
     method public void setBluetoothScoOn(boolean);
@@ -14160,10 +14167,10 @@
     method public void startBluetoothSco();
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
-    method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
-    method public void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
-    method public void unregisterRemoteControlClient(android.media.RemoteControlClient);
-    method public void unregisterRemoteController(android.media.RemoteController);
+    method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
+    method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
+    method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
+    method public deprecated void unregisterRemoteController(android.media.RemoteController);
     field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
@@ -14367,6 +14374,11 @@
     field public static final int QUALITY_720P = 5; // 0x5
     field public static final int QUALITY_CIF = 3; // 0x3
     field public static final int QUALITY_HIGH = 1; // 0x1
+    field public static final int QUALITY_HIGH_SPEED_1080P = 2004; // 0x7d4
+    field public static final int QUALITY_HIGH_SPEED_480P = 2002; // 0x7d2
+    field public static final int QUALITY_HIGH_SPEED_720P = 2003; // 0x7d3
+    field public static final int QUALITY_HIGH_SPEED_HIGH = 2001; // 0x7d1
+    field public static final int QUALITY_HIGH_SPEED_LOW = 2000; // 0x7d0
     field public static final int QUALITY_LOW = 0; // 0x0
     field public static final int QUALITY_QCIF = 2; // 0x2
     field public static final int QUALITY_QVGA = 7; // 0x7
@@ -14995,6 +15007,7 @@
     field public static final java.lang.String KEY_AAC_SBR_MODE = "aac-sbr-mode";
     field public static final java.lang.String KEY_BITRATE_MODE = "bitrate-mode";
     field public static final java.lang.String KEY_BIT_RATE = "bitrate";
+    field public static final java.lang.String KEY_CAPTURE_RATE = "capture-rate";
     field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
     field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
     field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
@@ -16174,7 +16187,7 @@
     method public android.net.Uri getRoot();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
-    method public void loadThumbnail(android.net.Uri, int, int, android.media.browse.MediaBrowser.ThumbnailCallback);
+    method public void loadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowser.IconCallback);
     method public void subscribe(android.net.Uri, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(android.net.Uri);
   }
@@ -16186,23 +16199,23 @@
     method public void onConnectionSuspended();
   }
 
+  public static abstract class MediaBrowser.IconCallback {
+    ctor public MediaBrowser.IconCallback();
+    method public void onError(android.net.Uri);
+    method public void onIconLoaded(android.net.Uri, android.graphics.Bitmap);
+  }
+
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(android.net.Uri, java.util.List<android.media.browse.MediaBrowserItem>);
     method public void onError(android.net.Uri);
   }
 
-  public static abstract class MediaBrowser.ThumbnailCallback {
-    ctor public MediaBrowser.ThumbnailCallback();
-    method public void onError(android.net.Uri);
-    method public void onThumbnailLoaded(android.net.Uri, android.graphics.Bitmap);
-  }
-
   public final class MediaBrowserItem implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.Bundle getExtras();
     method public int getFlags();
-    method public int getIconResId();
+    method public int getIconResourceId();
     method public android.net.Uri getIconUri();
     method public java.lang.CharSequence getSummary();
     method public java.lang.CharSequence getTitle();
@@ -16219,7 +16232,7 @@
     ctor public MediaBrowserItem.Builder(android.net.Uri, int, java.lang.CharSequence);
     method public android.media.browse.MediaBrowserItem build();
     method public android.media.browse.MediaBrowserItem.Builder setExtras(android.os.Bundle);
-    method public android.media.browse.MediaBrowserItem.Builder setIconResId(int);
+    method public android.media.browse.MediaBrowserItem.Builder setIconResourceId(int);
     method public android.media.browse.MediaBrowserItem.Builder setIconUri(android.net.Uri);
     method public android.media.browse.MediaBrowserItem.Builder setSummary(java.lang.CharSequence);
   }
@@ -16230,15 +16243,22 @@
     method public android.media.session.MediaSession.Token getSessionToken();
     method public void notifyChildrenChanged(android.net.Uri);
     method public android.os.IBinder onBind(android.content.Intent);
-    method protected abstract android.media.browse.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
-    method protected abstract android.graphics.Bitmap onGetThumbnail(android.net.Uri, int, int);
-    method protected abstract java.util.List<android.media.browse.MediaBrowserItem> onLoadChildren(android.net.Uri);
+    method public abstract android.media.browse.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
+    method public abstract void onLoadChildren(android.net.Uri, android.media.browse.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowserItem>>);
+    method public abstract void onLoadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowserService.Result<android.graphics.Bitmap>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
     field public static final java.lang.String SERVICE_ACTION = "android.media.browse.MediaBrowserService";
   }
 
-  public static class MediaBrowserService.BrowserRoot {
+  public static final class MediaBrowserService.BrowserRoot {
     ctor public MediaBrowserService.BrowserRoot(android.net.Uri, android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getRootUri();
+  }
+
+  public class MediaBrowserService.Result {
+    method public void detach();
+    method public void sendResult(T);
   }
 
 }
@@ -16559,26 +16579,34 @@
 package android.media.session {
 
   public final class MediaController {
-    ctor public MediaController(android.media.session.MediaSession.Token);
+    ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
     method public void addCallback(android.media.session.MediaController.Callback);
     method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler);
     method public void adjustVolume(int, int);
     method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate();
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+    method public long getFlags();
+    method public android.app.PendingIntent getLaunchActivity();
     method public android.media.MediaMetadata getMetadata();
+    method public java.lang.String getPackageName();
     method public android.media.session.PlaybackState getPlaybackState();
+    method public java.util.List<android.media.session.MediaSession.Track> getQueue();
     method public int getRatingType();
+    method public android.media.session.MediaSession.Token getSessionToken();
     method public android.media.session.MediaController.TransportControls getTransportControls();
     method public android.media.session.MediaController.VolumeInfo getVolumeInfo();
     method public void removeCallback(android.media.session.MediaController.Callback);
-    method public void sendControlCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void setVolumeTo(int, int);
   }
 
   public static abstract class MediaController.Callback {
     ctor public MediaController.Callback();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onMetadataChanged(android.media.MediaMetadata);
     method public void onPlaybackStateChanged(android.media.session.PlaybackState);
+    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.Track>);
+    method public void onQueueTitleChanged(java.lang.CharSequence);
     method public void onSessionEvent(java.lang.String, android.os.Bundle);
     method public void onVolumeInfoChanged(android.media.session.MediaController.VolumeInfo);
   }
@@ -16587,11 +16615,16 @@
     method public void fastForward();
     method public void pause();
     method public void play();
+    method public void playFromSearch(java.lang.String, android.os.Bundle);
+    method public void playUri(android.net.Uri, android.os.Bundle);
     method public void rewind();
     method public void seekTo(long);
+    method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
+    method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
     method public void skipToNext();
     method public void skipToPrevious();
+    method public void skipToTrack(long);
     method public void stop();
   }
 
@@ -16609,6 +16642,7 @@
     method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler);
     method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback);
     method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback, android.os.Handler);
+    method public android.media.session.MediaController getController();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isActive();
     method public void release();
@@ -16616,13 +16650,17 @@
     method public void removeTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback);
     method public void sendSessionEvent(java.lang.String, android.os.Bundle);
     method public void setActive(boolean);
+    method public void setExtras(android.os.Bundle);
     method public void setFlags(int);
-    method public void setLaunchPendingIntent(android.app.PendingIntent);
+    method public void setLaunchActivity(android.app.PendingIntent);
+    method public void setMediaButtonReceiver(android.app.PendingIntent);
     method public void setMediaRouter(android.media.routing.MediaRouter);
     method public void setMetadata(android.media.MediaMetadata);
     method public void setPlaybackState(android.media.session.PlaybackState);
     method public void setPlaybackToLocal(android.media.AudioAttributes);
     method public void setPlaybackToRemote(android.media.VolumeProvider);
+    method public void setQueue(java.util.List<android.media.session.MediaSession.Track>);
+    method public void setQueueTitle(java.lang.CharSequence);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
     field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
@@ -16631,7 +16669,7 @@
 
   public static abstract class MediaSession.Callback {
     ctor public MediaSession.Callback();
-    method public void onControlCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void onMediaButtonEvent(android.content.Intent);
   }
 
@@ -16641,26 +16679,48 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public static final class MediaSession.Track implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public long getId();
+    method public android.media.MediaMetadata getMetadata();
+    method public android.net.Uri getUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
+  }
+
+  public static final class MediaSession.Track.Builder {
+    ctor public MediaSession.Track.Builder(android.media.MediaMetadata, long, android.net.Uri);
+    method public android.media.session.MediaSession.Track build();
+    method public android.media.session.MediaSession.Track.Builder setExtras(android.os.Bundle);
+  }
+
   public static abstract class MediaSession.TransportControlsCallback {
     ctor public MediaSession.TransportControlsCallback();
+    method public void onCustomAction(java.lang.String, android.os.Bundle);
     method public void onFastForward();
     method public void onPause();
     method public void onPlay();
+    method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPlayUri(android.net.Uri, android.os.Bundle);
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
+    method public void onSkipToTrack(long);
     method public void onStop();
   }
 
   public final class MediaSessionManager {
     method public void addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, android.content.ComponentName);
     method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
+    method public void removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener);
   }
 
   public static abstract class MediaSessionManager.SessionListener {
-    ctor public MediaSessionManager.SessionListener();
+    ctor public MediaSessionManager.SessionListener(android.content.Context);
     method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
   }
 
@@ -16668,6 +16728,7 @@
     method public int describeContents();
     method public long getActions();
     method public long getBufferPosition();
+    method public java.util.List<android.media.session.PlaybackState.CustomAction> getCustomActions();
     method public java.lang.CharSequence getErrorMessage();
     method public long getLastPositionUpdateTime();
     method public float getPlaybackSpeed();
@@ -16677,12 +16738,15 @@
     field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
     field public static final long ACTION_PAUSE = 2L; // 0x2L
     field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
     field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+    field public static final long ACTION_PLAY_URI = 1024L; // 0x400L
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_TRACK = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
@@ -16702,14 +16766,33 @@
   public static final class PlaybackState.Builder {
     ctor public PlaybackState.Builder();
     ctor public PlaybackState.Builder(android.media.session.PlaybackState);
+    method public android.media.session.PlaybackState.Builder addCustomAction(java.lang.String, java.lang.String, int);
+    method public android.media.session.PlaybackState.Builder addCustomAction(android.media.session.PlaybackState.CustomAction);
     method public android.media.session.PlaybackState build();
     method public android.media.session.PlaybackState.Builder setActions(long);
+    method public android.media.session.PlaybackState.Builder setActiveTrack(long);
     method public android.media.session.PlaybackState.Builder setBufferPosition(long);
     method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence);
     method public android.media.session.PlaybackState.Builder setState(int, long, float, long);
     method public android.media.session.PlaybackState.Builder setState(int, long, float);
   }
 
+  public static final class PlaybackState.CustomAction implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getAction();
+    method public android.os.Bundle getExtras();
+    method public int getIcon();
+    method public java.lang.CharSequence getName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class PlaybackState.CustomAction.Builder {
+    ctor public PlaybackState.CustomAction.Builder(java.lang.String, java.lang.CharSequence, int);
+    method public android.media.session.PlaybackState.CustomAction build();
+    method public android.media.session.PlaybackState.CustomAction.Builder setExtras(android.os.Bundle);
+  }
+
 }
 
 package android.media.tv {
@@ -16760,7 +16843,6 @@
 
   public static final class TvContract.Channels implements android.media.tv.TvContract.BaseTvColumns {
     method public static final java.lang.String getVideoResolution(java.lang.String);
-    field public static final java.lang.String COLUMN_CONDITIONAL_ACCESS = "conditional_access";
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
     field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
     field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
@@ -16941,12 +17023,12 @@
 
   public abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
     ctor public TvInputService.Session();
-    method public void dispatchChannelRetuned(android.net.Uri);
-    method public void dispatchContentAllowed();
-    method public void dispatchContentBlocked(android.media.tv.TvContentRating);
-    method public void dispatchTrackInfoChanged(java.util.List<android.media.tv.TvTrackInfo>);
-    method public void dispatchVideoAvailable();
-    method public void dispatchVideoUnavailable(int);
+    method public void notifyChannelRetuned(android.net.Uri);
+    method public void notifyContentAllowed();
+    method public void notifyContentBlocked(android.media.tv.TvContentRating);
+    method public void notifyTrackInfoChanged(java.util.List<android.media.tv.TvTrackInfo>);
+    method public void notifyVideoAvailable();
+    method public void notifyVideoUnavailable(int);
     method public android.view.View onCreateOverlayView();
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
     method public boolean onKeyDown(int, android.view.KeyEvent);
@@ -16954,7 +17036,6 @@
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
     method public abstract void onRelease();
-    method public void onRequestUnblockContent(android.media.tv.TvContentRating);
     method public boolean onSelectTrack(android.media.tv.TvTrackInfo);
     method public abstract void onSetCaptionEnabled(boolean);
     method public abstract void onSetStreamVolume(float);
@@ -16963,6 +17044,7 @@
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public abstract boolean onTune(android.net.Uri);
+    method public void onUnblockContent(android.media.tv.TvContentRating);
     method public boolean onUnselectTrack(android.media.tv.TvTrackInfo);
     method public void setOverlayViewEnabled(boolean);
   }
@@ -17364,6 +17446,7 @@
   public class Network implements android.os.Parcelable {
     method public int describeContents();
     method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
+    method public java.net.URL getBoundURL(java.net.URL) throws java.net.MalformedURLException;
     method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
     method public javax.net.SocketFactory getSocketFactory();
     method public void writeToParcel(android.os.Parcel, int);
@@ -22645,7 +22728,7 @@
   public class UserManager {
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
-    method public java.lang.String getBadgedLabelForUser(java.lang.String, android.os.UserHandle);
+    method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
     method public android.os.UserHandle getUserForSerialNumber(long);
@@ -22672,6 +22755,7 @@
     field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
     field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
     field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows";
+    field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
     field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
     field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
     field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
@@ -23903,6 +23987,7 @@
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
+    field public static final java.lang.String TRANSCRIPTION = "transcription";
     field public static final java.lang.String TYPE = "type";
     field public static final int VOICEMAIL_TYPE = 4; // 0x4
     field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
@@ -24280,6 +24365,7 @@
   }
 
   public static final class ContactsContract.CommonDataKinds.Event implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
+    method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
     method public static int getTypeResource(java.lang.Integer);
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event";
     field public static final java.lang.String START_DATE = "data1";
@@ -24778,7 +24864,7 @@
     ctor public ContactsContract.PinnedPositions();
     field public static final int DEMOTED = -1; // 0xffffffff
     field public static final java.lang.String UNDEMOTE_METHOD = "undemote";
-    field public static final int UNPINNED = 2147483647; // 0x7fffffff
+    field public static final int UNPINNED = 0; // 0x0
   }
 
   public static final deprecated class ContactsContract.Presence extends android.provider.ContactsContract.StatusUpdates {
@@ -25464,11 +25550,13 @@
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
     field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
+    field public static final java.lang.String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
     field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
     field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
     field public static final java.lang.String AUTHORITY = "settings";
     field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
+    field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
     field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
   }
@@ -28138,6 +28226,8 @@
     field public static final int PROT_NONE;
     field public static final int PROT_READ;
     field public static final int PROT_WRITE;
+    field public static final int PR_GET_DUMPABLE;
+    field public static final int PR_SET_DUMPABLE;
     field public static final int PR_SET_NO_NEW_PRIVS;
     field public static final int RT_SCOPE_HOST;
     field public static final int RT_SCOPE_LINK;
@@ -28396,13 +28486,13 @@
     method public void answer(int);
     method public void conference();
     method public void disconnect();
-    method public android.telecomm.RemoteCallVideoProvider getCallVideoProvider();
     method public java.util.List<java.lang.String> getCannedTextResponses();
     method public java.util.List<android.telecomm.Call> getChildren();
     method public android.telecomm.Call.Details getDetails();
     method public android.telecomm.Call getParent();
     method public java.lang.String getRemainingPostDialSequence();
     method public int getState();
+    method public android.telecomm.InCallService.VideoCall getVideoCall();
     method public void hold();
     method public void phoneAccountClicked();
     method public void phoneAccountSelected(android.telecomm.PhoneAccountHandle);
@@ -28441,7 +28531,6 @@
   public static abstract class Call.Listener {
     ctor public Call.Listener();
     method public void onCallDestroyed(android.telecomm.Call);
-    method public void onCallVideoProviderChanged(android.telecomm.Call, android.telecomm.RemoteCallVideoProvider);
     method public void onCannedTextResponsesLoaded(android.telecomm.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecomm.Call, java.util.List<android.telecomm.Call>);
     method public void onDetailsChanged(android.telecomm.Call, android.telecomm.Call.Details);
@@ -28450,6 +28539,7 @@
     method public void onPostDialWait(android.telecomm.Call, java.lang.String);
     method public void onStartActivity(android.telecomm.Call, android.app.PendingIntent);
     method public void onStateChanged(android.telecomm.Call, int);
+    method public void onVideoCallChanged(android.telecomm.Call, android.telecomm.InCallService.VideoCall);
   }
 
   public final class CallAudioState implements android.os.Parcelable {
@@ -28513,53 +28603,25 @@
     enum_constant public static final android.telecomm.CallState RINGING;
   }
 
-  public abstract class CallVideoClient {
-    ctor public CallVideoClient();
-    method public abstract void onHandleCallSessionEvent(int);
-    method public abstract void onHandleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities);
-    method public abstract void onReceiveSessionModifyRequest(android.telecomm.VideoCallProfile);
-    method public abstract void onReceiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile);
-    method public abstract void onUpdateCallDataUsage(int);
-    method public abstract void onUpdatePeerDimensions(int, int);
-    field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
-    field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
-    field public static final int SESSION_EVENT_TX_START = 3; // 0x3
-    field public static final int SESSION_EVENT_TX_STOP = 4; // 0x4
-    field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
-    field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
-    field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1
-  }
-
-  public abstract class CallVideoProvider {
-    ctor public CallVideoProvider();
-    method public abstract void onRequestCallDataUsage();
-    method public abstract void onRequestCameraCapabilities();
-    method public abstract void onSendSessionModifyRequest(android.telecomm.VideoCallProfile);
-    method public abstract void onSendSessionModifyResponse(android.telecomm.VideoCallProfile);
-    method public abstract void onSetCallVideoClient(android.telecomm.RemoteCallVideoClient);
-    method public abstract void onSetCamera(java.lang.String);
-    method public abstract void onSetDeviceOrientation(int);
-    method public abstract void onSetDisplaySurface(android.view.Surface);
-    method public abstract void onSetPauseImage(java.lang.String);
-    method public abstract void onSetPreviewSurface(android.view.Surface);
-    method public abstract void onSetZoom(float);
-  }
-
   public abstract class Connection {
     ctor public Connection();
     method public final void destroy();
     method public final boolean getAudioModeIsVoip();
     method public final android.telecomm.CallAudioState getCallAudioState();
     method public final int getCallCapabilities();
-    method public final android.telecomm.CallVideoProvider getCallVideoProvider();
     method public final java.lang.String getCallerDisplayName();
     method public final int getCallerDisplayNamePresentation();
+    method public static android.telecomm.Connection getCanceledConnection();
     method public final java.util.List<android.telecomm.Connection> getChildConnections();
+    method public static android.telecomm.Connection getFailedConnection(int, java.lang.String);
+    method public final int getFailureCode();
+    method public final java.lang.String getFailureMessage();
     method public final android.net.Uri getHandle();
     method public final int getHandlePresentation();
     method public final android.telecomm.Connection getParentConnection();
     method public final int getState();
     method public final android.telecomm.StatusHints getStatusHints();
+    method public final android.telecomm.ConnectionService.VideoCallProvider getVideoCallProvider();
     method public final int getVideoState();
     method public final boolean isConferenceConnection();
     method public final boolean isRequestingRingback();
@@ -28581,11 +28643,14 @@
     method public final void setActive();
     method public final void setAudioModeIsVoip(boolean);
     method public final void setCallCapabilities(int);
-    method public final void setCallVideoProvider(android.telecomm.CallVideoProvider);
     method public final void setCallerDisplayName(java.lang.String, int);
+    method public final void setCanceled();
     method public final void setDialing();
     method public final void setDisconnected(int, java.lang.String);
+    method public final void setFailed(int, java.lang.String);
     method public final void setHandle(android.net.Uri, int);
+    method public final void setInitialized();
+    method public final void setInitializing();
     method public final void setOnHold();
     method public final void setParentConnection(android.telecomm.Connection);
     method public final void setPostDialWait(java.lang.String);
@@ -28593,18 +28658,22 @@
     method public final void setRinging();
     method public final void setSignal(android.os.Bundle);
     method public final void setStatusHints(android.telecomm.StatusHints);
+    method public final void setVideoCallProvider(android.telecomm.ConnectionService.VideoCallProvider);
     method public final void setVideoState(int);
     method public final void startActivityFromInCall(android.app.PendingIntent);
     method public static java.lang.String stateToString(int);
   }
 
   public final class Connection.State {
-    field public static final int ACTIVE = 3; // 0x3
-    field public static final int DIALING = 2; // 0x2
-    field public static final int DISCONNECTED = 5; // 0x5
-    field public static final int HOLDING = 4; // 0x4
-    field public static final int NEW = 0; // 0x0
-    field public static final int RINGING = 1; // 0x1
+    field public static final int ACTIVE = 4; // 0x4
+    field public static final int CANCELED = 8; // 0x8
+    field public static final int DIALING = 3; // 0x3
+    field public static final int DISCONNECTED = 6; // 0x6
+    field public static final int FAILED = 7; // 0x7
+    field public static final int HOLDING = 5; // 0x5
+    field public static final int INITIALIZING = 0; // 0x0
+    field public static final int NEW = 1; // 0x1
+    field public static final int RINGING = 2; // 0x2
   }
 
   public final class ConnectionRequest implements android.os.Parcelable {
@@ -28622,17 +28691,16 @@
 
   public abstract class ConnectionService extends android.app.Service {
     ctor public ConnectionService();
-    method public final void createRemoteIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.RemoteConnection>);
-    method public final void createRemoteOutgoingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.RemoteConnection>);
+    method public final android.telecomm.RemoteConnection createRemoteIncomingConnection(android.telecomm.ConnectionRequest);
+    method public final android.telecomm.RemoteConnection createRemoteOutgoingConnection(android.telecomm.ConnectionRequest);
     method public final java.util.Collection<android.telecomm.Connection> getAllConnections();
-    method public final void lookupRemoteAccounts(android.net.Uri, android.telecomm.SimpleResponse<android.net.Uri, java.util.List<android.telecomm.PhoneAccountHandle>>);
     method public final void maybeRespondToAccountLookup();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnectionAdded(android.telecomm.Connection);
     method public void onConnectionRemoved(android.telecomm.Connection);
     method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
-    method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.Connection>);
-    method public void onCreateOutgoingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.Connection>);
+    method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.ConnectionRequest);
+    method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.ConnectionRequest);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecomm.ConnectionService";
   }
 
@@ -28642,6 +28710,26 @@
     method public abstract void onSuccess(android.telecomm.ConnectionRequest, CONNECTION);
   }
 
+  public static abstract class ConnectionService.VideoCallProvider {
+    ctor public ConnectionService.VideoCallProvider();
+    method public void changeCallDataUsage(int);
+    method public void changeCameraCapabilities(android.telecomm.CallCameraCapabilities);
+    method public void changePeerDimensions(int, int);
+    method public void handleCallSessionEvent(int);
+    method public abstract void onRequestCallDataUsage();
+    method public abstract void onRequestCameraCapabilities();
+    method public abstract void onSendSessionModifyRequest(android.telecomm.VideoCallProfile);
+    method public abstract void onSendSessionModifyResponse(android.telecomm.VideoCallProfile);
+    method public abstract void onSetCamera(java.lang.String);
+    method public abstract void onSetDeviceOrientation(int);
+    method public abstract void onSetDisplaySurface(android.view.Surface);
+    method public abstract void onSetPauseImage(java.lang.String);
+    method public abstract void onSetPreviewSurface(android.view.Surface);
+    method public abstract void onSetZoom(float);
+    method public void receiveSessionModifyRequest(android.telecomm.VideoCallProfile);
+    method public void receiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile);
+  }
+
   public class GatewayInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.Uri getGatewayHandle();
@@ -28676,6 +28764,38 @@
     method public void onPhoneDestroyed(android.telecomm.Phone);
   }
 
+  public static abstract class InCallService.VideoCall {
+    ctor public InCallService.VideoCall();
+    method public abstract void requestCallDataUsage();
+    method public abstract void requestCameraCapabilities();
+    method public abstract void sendSessionModifyRequest(android.telecomm.VideoCallProfile);
+    method public abstract void sendSessionModifyResponse(android.telecomm.VideoCallProfile);
+    method public abstract void setCamera(java.lang.String);
+    method public abstract void setDeviceOrientation(int);
+    method public abstract void setDisplaySurface(android.view.Surface);
+    method public abstract void setPauseImage(java.lang.String);
+    method public abstract void setPreviewSurface(android.view.Surface);
+    method public abstract void setVideoCallListener(android.telecomm.InCallService.VideoCall.Listener);
+    method public abstract void setZoom(float);
+    field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
+    field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
+    field public static final int SESSION_EVENT_TX_START = 3; // 0x3
+    field public static final int SESSION_EVENT_TX_STOP = 4; // 0x4
+    field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
+    field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
+    field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1
+  }
+
+  public static abstract class InCallService.VideoCall.Listener {
+    ctor public InCallService.VideoCall.Listener();
+    method public abstract void onCallDataUsageChanged(int);
+    method public abstract void onCallSessionEvent(int);
+    method public abstract void onCameraCapabilitiesChanged(android.telecomm.CallCameraCapabilities);
+    method public abstract void onPeerDimensionsChanged(int, int);
+    method public abstract void onSessionModifyRequestReceived(android.telecomm.VideoCallProfile);
+    method public abstract void onSessionModifyResponseReceived(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile);
+  }
+
   public final class Phone {
     method public final void addListener(android.telecomm.Phone.Listener);
     method public final android.telecomm.CallAudioState getAudioState();
@@ -28720,29 +28840,6 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
-  public class RemoteCallVideoClient {
-    method public void handleCallSessionEvent(int);
-    method public void handleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities);
-    method public void receiveSessionModifyRequest(android.telecomm.VideoCallProfile);
-    method public void receiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile);
-    method public void updateCallDataUsage(int);
-    method public void updatePeerDimensions(int, int);
-  }
-
-  public class RemoteCallVideoProvider {
-    method public void requestCallDataUsage();
-    method public void requestCameraCapabilities();
-    method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile);
-    method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile);
-    method public void setCallVideoClient(android.telecomm.CallVideoClient);
-    method public void setCamera(java.lang.String);
-    method public void setDeviceOrientation(int);
-    method public void setDisplaySurface(android.view.Surface);
-    method public void setPauseImage(java.lang.String);
-    method public void setPreviewSurface(android.view.Surface);
-    method public void setZoom(float);
-  }
-
   public final class RemoteConnection {
     method public void abort();
     method public void addListener(android.telecomm.RemoteConnection.Listener);
@@ -28754,6 +28851,8 @@
     method public int getCallerDisplayNamePresentation();
     method public int getDisconnectCause();
     method public java.lang.String getDisconnectMessage();
+    method public int getFailureCode();
+    method public java.lang.String getFailureMessage();
     method public android.net.Uri getHandle();
     method public int getHandlePresentation();
     method public int getState();
@@ -28770,19 +28869,20 @@
     method public void unhold();
   }
 
-  public static abstract interface RemoteConnection.Listener {
-    method public abstract void onAudioModeIsVoipChanged(android.telecomm.RemoteConnection, boolean);
-    method public abstract void onCallCapabilitiesChanged(android.telecomm.RemoteConnection, int);
-    method public abstract void onCallerDisplayNameChanged(android.telecomm.RemoteConnection, java.lang.String, int);
-    method public abstract void onDestroyed(android.telecomm.RemoteConnection);
-    method public abstract void onDisconnected(android.telecomm.RemoteConnection, int, java.lang.String);
-    method public abstract void onHandleChanged(android.telecomm.RemoteConnection, android.net.Uri, int);
-    method public abstract void onPostDialWait(android.telecomm.RemoteConnection, java.lang.String);
-    method public abstract void onRequestingRingback(android.telecomm.RemoteConnection, boolean);
-    method public abstract void onStartActivityFromInCall(android.telecomm.RemoteConnection, android.app.PendingIntent);
-    method public abstract void onStateChanged(android.telecomm.RemoteConnection, int);
-    method public abstract void onStatusHintsChanged(android.telecomm.RemoteConnection, android.telecomm.StatusHints);
-    method public abstract void onVideoStateChanged(android.telecomm.RemoteConnection, int);
+  public static abstract class RemoteConnection.Listener {
+    ctor public RemoteConnection.Listener();
+    method public void onAudioModeIsVoipChanged(android.telecomm.RemoteConnection, boolean);
+    method public void onCallCapabilitiesChanged(android.telecomm.RemoteConnection, int);
+    method public void onCallerDisplayNameChanged(android.telecomm.RemoteConnection, java.lang.String, int);
+    method public void onDestroyed(android.telecomm.RemoteConnection);
+    method public void onDisconnected(android.telecomm.RemoteConnection, int, java.lang.String);
+    method public void onHandleChanged(android.telecomm.RemoteConnection, android.net.Uri, int);
+    method public void onPostDialWait(android.telecomm.RemoteConnection, java.lang.String);
+    method public void onRequestingRingback(android.telecomm.RemoteConnection, boolean);
+    method public void onStartActivityFromInCall(android.telecomm.RemoteConnection, android.app.PendingIntent);
+    method public void onStateChanged(android.telecomm.RemoteConnection, int);
+    method public void onStatusHintsChanged(android.telecomm.RemoteConnection, android.telecomm.StatusHints);
+    method public void onVideoStateChanged(android.telecomm.RemoteConnection, int);
   }
 
   public abstract interface Response {
@@ -28813,6 +28913,7 @@
     method public android.telecomm.PhoneAccountHandle getDefaultOutgoingPhoneAccount();
     method public java.util.List<android.telecomm.PhoneAccountHandle> getEnabledPhoneAccounts();
     method public android.telecomm.PhoneAccount getPhoneAccount(android.telecomm.PhoneAccountHandle);
+    method public boolean hasMultipleEnabledAccounts();
     method public void registerPhoneAccount(android.telecomm.PhoneAccount);
     method public void unregisterPhoneAccount(android.telecomm.PhoneAccountHandle);
     field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.intent.action.CONNECTION_SERVICE_CONFIGURE";
@@ -28828,6 +28929,20 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.intent.extra.START_CALL_WITH_VIDEO_STATE";
   }
 
+  public class VideoCallImpl extends android.telecomm.InCallService.VideoCall {
+    method public void requestCallDataUsage();
+    method public void requestCameraCapabilities();
+    method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile);
+    method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile);
+    method public void setCamera(java.lang.String);
+    method public void setDeviceOrientation(int);
+    method public void setDisplaySurface(android.view.Surface);
+    method public void setPauseImage(java.lang.String);
+    method public void setPreviewSurface(android.view.Surface);
+    method public void setVideoCallListener(android.telecomm.InCallService.VideoCall.Listener);
+    method public void setZoom(float);
+  }
+
   public class VideoCallProfile implements android.os.Parcelable {
     ctor public VideoCallProfile(int);
     ctor public VideoCallProfile(int, int);
@@ -29028,7 +29143,7 @@
     field public static final int LIMIT_EXCEEDED = 15; // 0xf
     field public static final int LOCAL = 3; // 0x3
     field public static final int LOST_SIGNAL = 14; // 0xe
-    field public static final int MAXIMUM_VALID_VALUE = 42; // 0x2a
+    field public static final int MAXIMUM_VALID_VALUE = 44; // 0x2c
     field public static final int MINIMUM_VALID_VALUE = 0; // 0x0
     field public static final int MMI = 6; // 0x6
     field public static final int NORMAL = 2; // 0x2
@@ -29036,6 +29151,8 @@
     field public static final int NOT_VALID = -1; // 0xffffffff
     field public static final int NO_PHONE_NUMBER_SUPPLIED = 38; // 0x26
     field public static final int NUMBER_UNREACHABLE = 8; // 0x8
+    field public static final int OUTGOING_CANCELED = 44; // 0x2c
+    field public static final int OUTGOING_FAILURE = 43; // 0x2b
     field public static final int OUT_OF_NETWORK = 11; // 0xb
     field public static final int OUT_OF_SERVICE = 18; // 0x12
     field public static final int POWER_OFF = 17; // 0x11
@@ -30050,7 +30167,6 @@
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
-    method public android.content.pm.PackageInstaller getInstaller();
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
@@ -30059,6 +30175,7 @@
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.content.pm.PackageInstaller getPackageInstaller();
     method public java.lang.String[] getPackagesForUid(int);
     method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -36649,7 +36766,7 @@
     method public void removeSessionCookies(android.webkit.ValueCallback<java.lang.Boolean>);
     method public synchronized void setAcceptCookie(boolean);
     method public static void setAcceptFileSchemeCookies(boolean);
-    method public synchronized void setAcceptThirdPartyCookies(android.webkit.WebView, boolean);
+    method public void setAcceptThirdPartyCookies(android.webkit.WebView, boolean);
     method public void setCookie(java.lang.String, java.lang.String);
     method public void setCookie(java.lang.String, java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>);
   }
@@ -36715,15 +36832,15 @@
     method public boolean hasMimeType(java.lang.String);
   }
 
-  public abstract interface PermissionRequest {
+  public abstract class PermissionRequest {
+    ctor public PermissionRequest();
     method public abstract void deny();
     method public abstract android.net.Uri getOrigin();
-    method public abstract long getResources();
-    method public abstract void grant(long);
-    field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
-    field public static final long RESOURCE_GEOLOCATION = 1L; // 0x1L
-    field public static final long RESOURCE_PROTECTED_MEDIA_ID = 8L; // 0x8L
-    field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
+    method public abstract java.lang.String[] getResources();
+    method public abstract void grant(java.lang.String[]);
+    field public static final java.lang.String RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE";
+    field public static final java.lang.String RESOURCE_PROTECTED_MEDIA_ID = "android.webkit.resource.PROTECTED_MEDIA_ID";
+    field public static final java.lang.String RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE";
   }
 
   public abstract interface PluginStub {
@@ -36795,23 +36912,31 @@
     method public void onRequestFocus(android.webkit.WebView);
     method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback);
     method public deprecated void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
-    method public boolean showFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams);
+    method public boolean onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams);
   }
 
   public static abstract interface WebChromeClient.CustomViewCallback {
     method public abstract void onCustomViewHidden();
   }
 
-  public static class WebChromeClient.FileChooserParams {
+  public static abstract class WebChromeClient.FileChooserParams {
     ctor public WebChromeClient.FileChooserParams();
-    field public static final int MODE_OPEN_FOLDER = 2; // 0x2
-    field public static final int MODE_OPEN_MULTIPLE = 1; // 0x1
-    field public static final int MODE_SAVE = 4; // 0x4
-    field public java.lang.String acceptTypes;
-    field public boolean capture;
-    field public java.lang.String defaultFilename;
-    field public int mode;
-    field public java.lang.String title;
+    method public abstract java.lang.String[] getAcceptTypes();
+    method public abstract java.lang.String getDefaultFilename();
+    method public abstract int getMode();
+    method public abstract java.lang.CharSequence getTitle();
+    method public abstract android.webkit.WebChromeClient.UploadHelper getUploadHelper();
+    method public abstract boolean isCaptureEnabled();
+    field public static final int OPEN = 0; // 0x0
+    field public static final int OPEN_FOLDER = 2; // 0x2
+    field public static final int OPEN_MULTIPLE = 1; // 0x1
+    field public static final int SAVE = 3; // 0x3
+  }
+
+  public static abstract class WebChromeClient.UploadHelper {
+    ctor public WebChromeClient.UploadHelper();
+    method public abstract android.content.Intent buildIntent();
+    method public abstract android.net.Uri[] parseResult(int, android.content.Intent);
   }
 
   public class WebHistoryItem implements java.lang.Cloneable {
@@ -37063,6 +37188,7 @@
     method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
     method public void destroy();
     method public void documentHasImages(android.os.Message);
+    method public static void enableSlowWholeDocumentDraw();
     method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
     method public static java.lang.String findAddress(java.lang.String);
     method public deprecated int findAll(java.lang.String);
@@ -37102,7 +37228,6 @@
     method public boolean pageUp(boolean);
     method public void pauseTimers();
     method public void postUrl(java.lang.String, byte[]);
-    method public void preauthorizePermission(android.net.Uri, long);
     method public void reload();
     method public void removeJavascriptInterface(java.lang.String);
     method public void requestFocusNodeHref(android.os.Message);
@@ -39661,10 +39786,8 @@
     method public void setLogo(android.graphics.drawable.Drawable);
     method public void setLogoDescription(int);
     method public void setLogoDescription(java.lang.CharSequence);
-    method public void setNavigationContentDescription(java.lang.CharSequence);
     method public void setNavigationContentDescription(int);
-    method public void setNavigationDescription(int);
-    method public void setNavigationDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(java.lang.CharSequence);
     method public void setNavigationIcon(int);
     method public void setNavigationIcon(android.graphics.drawable.Drawable);
     method public void setNavigationOnClickListener(android.view.View.OnClickListener);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 127b0fc..fa59e4b 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -1465,7 +1465,7 @@
 
         System.out.println("Performing idle maintenance...");
         Intent intent = new Intent(
-                "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE");
+                "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE");
         mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
                 android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL);
     }
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index c771f65..7757b91c 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -19,16 +19,17 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
 import android.media.session.ISessionController;
+import android.media.session.ISessionControllerCallback;
 import android.media.session.ISessionManager;
 import android.media.session.MediaController;
-import android.media.session.MediaSessionInfo;
+import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -62,14 +63,14 @@
                 "usage: media [subcommand] [options]\n" +
                 "       media dispatch KEY\n" +
                 "       media list-sessions\n" +
-                "       media monitor <sessionId>\n" +
+                "       media monitor <tag>\n" +
                 "\n" +
                 "media dispatch: dispatch a media key to the system.\n" +
                 "                KEY may be: play, pause, play-pause, mute, headsethook,\n" +
                 "                stop, next, previous, rewind, record, fast-forword.\n" +
                 "media list-sessions: print a list of the current sessions.\n" +
                         "media monitor: monitor updates to the specified session.\n" +
-                "                       Use the sessionId from list-sessions.\n"
+                "                       Use the tag from list-sessions.\n"
         );
     }
 
@@ -114,13 +115,16 @@
             List<IBinder> sessions = mSessionService
                     .getSessions(null, ActivityManager.getCurrentUser());
             for (IBinder session : sessions) {
-                MediaController controller = new MediaController(ISessionController.Stub
-                        .asInterface(session));
-                if (controller != null && controller.getSessionInfo().getId().equals(id)) {
-                    ControllerMonitor monitor = new ControllerMonitor(controller);
-                    monitor.run();
-                    success = true;
-                    break;
+                ISessionController controller = ISessionController.Stub.asInterface(session);
+                try {
+                    if (controller != null && id.equals(controller.getTag())) {
+                        ControllerMonitor monitor = new ControllerMonitor(controller);
+                        monitor.run();
+                        success = true;
+                        break;
+                    }
+                } catch (RemoteException e) {
+                    // ignore
                 }
             }
         } catch (Exception e) {
@@ -168,14 +172,14 @@
                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
     }
 
-    class ControllerMonitor extends MediaController.Callback {
-        private final MediaController mController;
+    class ControllerMonitor extends ISessionControllerCallback.Stub {
+        private final ISessionController mController;
 
-        public ControllerMonitor(MediaController controller) {
+        public ControllerMonitor(ISessionController controller) {
             mController = controller;
         }
         @Override
-        public void onSessionEvent(String event, Bundle extras) {
+        public void onEvent(String event, Bundle extras) {
             System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
         }
 
@@ -191,9 +195,33 @@
             System.out.println("onMetadataChanged " + mmString);
         }
 
+        @Override
+        public void onQueueChanged(ParceledListSlice queue) throws RemoteException {
+            System.out.println("onQueueChanged, size=" + queue.getList().size());
+        }
+
+        @Override
+        public void onQueueTitleChanged(CharSequence title) throws RemoteException {
+            System.out.println("onQueueTitleChange " + title);
+        }
+
+        @Override
+        public void onExtrasChanged(Bundle extras) throws RemoteException {
+            System.out.println("onExtrasChanged " + extras);
+        }
+
+        @Override
+        public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException {
+            System.out.println("onVolumeInfoChanged " + info);
+        }
+
         void printUsageMessage() {
-            System.out.println("V2Monitoring session " + mController.getSessionInfo().getId()
-                    + "...  available commands:");
+            try {
+                System.out.println("V2Monitoring session " + mController.getTag()
+                        + "...  available commands:");
+            } catch (RemoteException e) {
+                System.out.println("Error trying to monitor session!");
+            }
             System.out.println("(q)uit: finish monitoring");
         }
 
@@ -202,7 +230,11 @@
             HandlerThread cbThread = new HandlerThread("MediaCb") {
                 @Override
                 protected void onLooperPrepared() {
-                    mController.addCallback(ControllerMonitor.this);
+                    try {
+                        mController.registerCallbackListener(ControllerMonitor.this);
+                    } catch (RemoteException e) {
+                        System.out.println("Error registering monitor callback");
+                    }
                 }
             };
             cbThread.start();
@@ -234,7 +266,7 @@
             } finally {
                 cbThread.getLooper().quit();
                 try {
-                    mController.removeCallback(this);
+                    mController.unregisterCallbackListener(this);
                 } catch (Exception e) {
                     // ignoring
                 }
@@ -248,12 +280,15 @@
             List<IBinder> sessions = mSessionService
                     .getSessions(null, ActivityManager.getCurrentUser());
             for (IBinder session : sessions) {
-                MediaController controller = new MediaController(ISessionController.Stub
-                        .asInterface(session));
+
+                ISessionController controller = ISessionController.Stub.asInterface(session);
                 if (controller != null) {
-                    MediaSessionInfo info = controller.getSessionInfo();
-                    System.out.println("  id=" + info.getId() + ", package="
-                            + info.getPackageName());
+                    try {
+                        System.out.println("  tag=" + controller.getTag()
+                                + ", package=" + controller.getPackageName());
+                    } catch (RemoteException e) {
+                        // ignore
+                    }
                 }
             }
         } catch (Exception e) {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index faf5622..bc16800 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -27,11 +27,12 @@
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageManager;
+import android.content.pm.InstallSessionInfo;
 import android.content.pm.InstallSessionParams;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.CommitResultCallback;
+import android.content.pm.PackageInstaller.CommitCallback;
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
@@ -157,8 +158,8 @@
             return;
         }
 
-        if ("install-destroy".equals(op)) {
-            runInstallDestroy();
+        if ("install-abandon".equals(op) || "install-destroy".equals(op)) {
+            runInstallAbandon();
             return;
         }
 
@@ -252,6 +253,11 @@
             return;
         }
 
+        if ("force-dex-opt".equals(op)) {
+            runForceDexOpt();
+            return;
+        }
+
         try {
             if (args.length == 1) {
                 if (args[0].equalsIgnoreCase("-l")) {
@@ -770,7 +776,7 @@
         }
     }
 
-    class LocalCommitResultCallback extends CommitResultCallback {
+    class LocalCommitCallback extends CommitCallback {
         boolean finished;
         boolean success;
         String msg;
@@ -790,7 +796,7 @@
         }
 
         @Override
-        public void onFailure(String msg) {
+        public void onFailure(int failureReason, String msg, Bundle extras) {
             setResult(false, msg);
         }
     }
@@ -996,10 +1002,9 @@
     private void runInstallCreate() throws RemoteException {
         String installerPackageName = null;
 
-        final InstallSessionParams params = new InstallSessionParams();
+        final InstallSessionParams params = new InstallSessionParams(
+                InstallSessionParams.MODE_FULL_INSTALL);
         params.installFlags = PackageManager.INSTALL_ALL_USERS;
-        params.setModeFullInstall();
-        params.setProgressMax(-1);
 
         String opt;
         while ((opt = nextOption()) != null) {
@@ -1021,11 +1026,9 @@
             } else if (opt.equals("-d")) {
                 params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
             } else if (opt.equals("-p")) {
-                params.setModeInheritExisting();
+                params.mode = InstallSessionParams.MODE_INHERIT_EXISTING;
             } else if (opt.equals("-S")) {
-                final long deltaSize = Long.parseLong(nextOptionData());
-                params.setDeltaSize(deltaSize);
-                params.setProgressMax((int) params.deltaSize);
+                params.setSize(Long.parseLong(nextOptionData()));
             } else if (opt.equals("--abi")) {
                 params.abiOverride = checkAbiArgument(nextOptionData());
             } else {
@@ -1033,7 +1036,7 @@
             }
         }
 
-        final int sessionId = mInstaller.createSession(installerPackageName, params,
+        final int sessionId = mInstaller.createSession(params, installerPackageName,
                 UserHandle.USER_OWNER);
 
         // NOTE: adb depends on parsing this string
@@ -1080,7 +1083,12 @@
 
             final int n = Streams.copy(in, out);
             session.fsync(out);
-            session.addProgress(n);
+
+            final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId);
+            if (info.sizeBytes > 0) {
+                final float fraction = ((float) n / (float) info.sizeBytes);
+                session.addProgress(fraction);
+            }
 
             System.out.println("Success: streamed " + n + " bytes");
         } finally {
@@ -1097,7 +1105,7 @@
         try {
             session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
 
-            final LocalCommitResultCallback callback = new LocalCommitResultCallback();
+            final LocalCommitCallback callback = new LocalCommitCallback();
             session.commit(callback);
 
             synchronized (callback) {
@@ -1118,13 +1126,13 @@
         }
     }
 
-    private void runInstallDestroy() throws RemoteException {
+    private void runInstallAbandon() throws RemoteException {
         final int sessionId = Integer.parseInt(nextArg());
 
         PackageInstaller.Session session = null;
         try {
             session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
-            session.destroy();
+            session.abandon();
             System.out.println("Success");
         } finally {
             IoUtils.closeQuietly(session);
@@ -1245,6 +1253,15 @@
         System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers());
     }
 
+    public void runForceDexOpt() {
+        final String packageName = nextArg();
+        try {
+            mPm.forceDexOpt(packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
         boolean finished;
         boolean result;
@@ -1743,7 +1760,7 @@
         System.err.println("       pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
         System.err.println("       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
         System.err.println("       pm install-commit SESSION_ID");
-        System.err.println("       pm install-destroy SESSION_ID");
+        System.err.println("       pm install-abandon SESSION_ID");
         System.err.println("       pm uninstall [-k] [--user USER_ID] PACKAGE");
         System.err.println("       pm set-installer PACKAGE INSTALLER");
         System.err.println("       pm clear [--user USER_ID] PACKAGE");
@@ -1813,7 +1830,7 @@
         System.err.println("    -S: size in bytes of package, required for stdin");
         System.err.println("");
         System.err.println("pm install-commit: perform install of fully staged session");
-        System.err.println("pm install-destroy: destroy session");
+        System.err.println("pm install-abandon: abandon session");
         System.err.println("");
         System.err.println("pm set-installer: set installer package name");
         System.err.println("");
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 19a91a6..13ceb4a 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -23,7 +23,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityEvent;
@@ -659,16 +658,12 @@
      */
     public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
             implements HandlerCaller.Callback {
-
-        static final int NO_ID = -1;
-
         private static final int DO_SET_SET_CONNECTION = 1;
         private static final int DO_ON_INTERRUPT = 2;
         private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
         private static final int DO_ON_GESTURE = 4;
         private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
         private static final int DO_ON_KEY_EVENT = 6;
-        private static final int DO_ON_WINDOWS_CHANGED = 7;
 
         private final HandlerCaller mCaller;
 
@@ -715,12 +710,6 @@
         }
 
         @Override
-        public void onWindowsChanged(int[] windowIds) {
-            Message message = mCaller.obtainMessageO(DO_ON_WINDOWS_CHANGED, windowIds);
-            mCaller.sendMessage(message);
-        }
-
-        @Override
         public void executeMessage(Message message) {
             switch (message.what) {
                 case DO_ON_ACCESSIBILITY_EVENT: {
@@ -791,31 +780,6 @@
                     }
                 } return;
 
-                case DO_ON_WINDOWS_CHANGED: {
-                    final int[] windowIds = (int[]) message.obj;
-
-                    // Update the cached windows first.
-                    // NOTE: The cache will hold on to the windows so do not recycle.
-                    if (windowIds != null) {
-                        AccessibilityInteractionClient.getInstance().removeWindows(windowIds);
-                    }
-
-                    // Let the client know the windows changed.
-                    AccessibilityEvent event = AccessibilityEvent.obtain(
-                            AccessibilityEvent.TYPE_WINDOWS_CHANGED);
-                    event.setEventTime(SystemClock.uptimeMillis());
-                    event.setSealed(true);
-
-                    mCallback.onAccessibilityEvent(event);
-
-                    // Make sure the event is recycled.
-                    try {
-                        event.recycle();
-                    } catch (IllegalStateException ise) {
-                        /* ignore - best effort */
-                    }
-                } break;
-
                 default :
                     Log.w(LOG_TAG, "Unknown message type " + message.what);
             }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index edd8727..6ce0219 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -39,6 +39,4 @@
     void clearAccessibilityCache();
 
     void onKeyEvent(in KeyEvent event, int sequence);
-
-    void onWindowsChanged(in int[] changedWindowIds);
 }
diff --git a/core/java/android/accounts/CantAddAccountActivity.java b/core/java/android/accounts/CantAddAccountActivity.java
index 4ac2beb..f7f232e 100644
--- a/core/java/android/accounts/CantAddAccountActivity.java
+++ b/core/java/android/accounts/CantAddAccountActivity.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
-import android.widget.TextView;
 
 import com.android.internal.R;
 
@@ -29,25 +28,11 @@
  */
 public class CantAddAccountActivity extends Activity {
     public static final String EXTRA_ERROR_CODE = "android.accounts.extra.ERROR_CODE";
-    public static final int MISSING = -1;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.app_not_authorized);
-
-        int errorCode = getIntent().getIntExtra(EXTRA_ERROR_CODE, MISSING);
-        if (errorCode != MISSING) {
-            TextView errorText = (TextView) findViewById(R.id.description);
-            switch (errorCode) {
-                case AccountManager.ERROR_CODE_USER_RESTRICTED:
-                    errorText.setText(R.string.app_no_restricted_accounts);
-                    break;
-                default:
-                    // TODO: Get better message. See: http://b/14642886
-                    errorText.setText(R.string.error_message_title);
-            }
-        }
     }
 
     public void onCancelButtonClicked(View view) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cac646d..394175a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -467,7 +467,7 @@
  *
  *     static final int PICK_CONTACT_REQUEST = 0;
  *
- *     protected boolean onKeyDown(int keyCode, KeyEvent event) {
+ *     public boolean onKeyDown(int keyCode, KeyEvent event) {
  *         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
  *             // When the user center presses, let them pick a contact.
  *             startActivityForResult(
@@ -5501,6 +5501,14 @@
     }
 
     /**
+     * Activities cannot draw during the period that their windows are animating in. In order
+     * to know when it is safe to begin drawing they can override this method which will be
+     * called when the entering animation has completed.
+     */
+    public void onEnterAnimationComplete() {
+    }
+
+    /**
      * Adjust the current immersive mode setting.
      *
      * Note that changing this value will have no effect on the activity's
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d43db78..fc200550 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -697,7 +697,6 @@
 
         /**
          * Task affiliation for grouping with other tasks.
-         * @hide
          */
         public int affiliatedTaskId;
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 342155d..311a8f55 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1661,8 +1661,10 @@
             String targetPkg = data.readString();
             Uri uri = Uri.CREATOR.createFromParcel(data);
             int mode = data.readInt();
-            int userId = data.readInt();
-            grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, userId);
+            int sourceUserId = data.readInt();
+            int targetUserId = data.readInt();
+            grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, sourceUserId,
+                    targetUserId);
             reply.writeNoException();
             return true;
         }
@@ -2229,6 +2231,14 @@
             reply.writeNoException();
             return true;
         }
+
+        case NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            notifyEnterAnimationComplete(token);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -4343,7 +4353,7 @@
     }
 
     public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
-            Uri uri, int mode, int userId) throws RemoteException {
+            Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4352,7 +4362,8 @@
         data.writeString(targetPkg);
         uri.writeToParcel(data, 0);
         data.writeInt(mode);
-        data.writeInt(userId);
+        data.writeInt(sourceUserId);
+        data.writeInt(targetUserId);
         mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -5143,5 +5154,18 @@
         reply.recycle();
     }
 
+    @Override
+    public void notifyEnterAnimationComplete(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION, data, reply,
+                IBinder.FLAG_ONEWAY);
+        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 48954f4..de5b9c4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1163,6 +1163,10 @@
         public void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean playing) {
             sendMessage(H.BACKGROUND_MEDIA_PLAYING_CHANGED, token, playing ? 1 : 0);
         }
+
+        public void scheduleEnterAnimationComplete(IBinder token) {
+            sendMessage(H.ENTER_ANIMATION_COMPLETE, token);
+        }
     }
 
     private class H extends Handler {
@@ -1215,6 +1219,7 @@
         public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
         public static final int STOP_MEDIA_PLAYING = 147;
         public static final int BACKGROUND_MEDIA_PLAYING_CHANGED = 148;
+        public static final int ENTER_ANIMATION_COMPLETE = 149;
 
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
@@ -1267,6 +1272,7 @@
                     case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS";
                     case STOP_MEDIA_PLAYING: return "STOP_MEDIA_PLAYING";
                     case BACKGROUND_MEDIA_PLAYING_CHANGED: return "BACKGROUND_MEDIA_PLAYING_CHANGED";
+                    case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
                 }
             }
             return Integer.toString(code);
@@ -1491,6 +1497,9 @@
                 case BACKGROUND_MEDIA_PLAYING_CHANGED:
                     handleOnBackgroundMediaPlayingChanged((IBinder) msg.obj, msg.arg1 > 0);
                     break;
+                case ENTER_ANIMATION_COMPLETE:
+                    handleEnterAnimationComplete((IBinder) msg.obj);
+                    break;
             }
             if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
         }
@@ -2196,6 +2205,7 @@
                     cl, component.getClassName(), r.intent);
             StrictMode.incrementExpectedActivityCount(activity.getClass());
             r.intent.setExtrasClassLoader(cl);
+            r.intent.prepareToEnterProcess();
             if (r.state != null) {
                 r.state.setClassLoader(cl);
             }
@@ -2420,6 +2430,7 @@
         for (int i=0; i<N; i++) {
             Intent intent = intents.get(i);
             intent.setExtrasClassLoader(r.activity.getClassLoader());
+            intent.prepareToEnterProcess();
             r.activity.mFragments.noteStateNotSaved();
             mInstrumentation.callActivityOnNewIntent(r.activity, intent);
         }
@@ -2509,6 +2520,13 @@
         installContentProviders(mInitialApplication, Lists.newArrayList(info));
     }
 
+    private void handleEnterAnimationComplete(IBinder token) {
+        ActivityClientRecord r = mActivities.get(token);
+        if (r != null) {
+            r.activity.onEnterAnimationComplete();
+        }
+    }
+
     private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
 
     /**
@@ -2536,6 +2554,7 @@
         try {
             java.lang.ClassLoader cl = packageInfo.getClassLoader();
             data.intent.setExtrasClassLoader(cl);
+            data.intent.prepareToEnterProcess();
             data.setExtrasClassLoader(cl);
             receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
         } catch (Exception e) {
@@ -2737,6 +2756,7 @@
         if (s != null) {
             try {
                 data.intent.setExtrasClassLoader(s.getClassLoader());
+                data.intent.prepareToEnterProcess();
                 try {
                     if (!data.rebind) {
                         IBinder binder = s.onBind(data.intent);
@@ -2765,6 +2785,7 @@
         if (s != null) {
             try {
                 data.intent.setExtrasClassLoader(s.getClassLoader());
+                data.intent.prepareToEnterProcess();
                 boolean doRebind = s.onUnbind(data.intent);
                 try {
                     if (doRebind) {
@@ -2840,6 +2861,7 @@
             try {
                 if (data.args != null) {
                     data.args.setExtrasClassLoader(s.getClassLoader());
+                    data.args.prepareToEnterProcess();
                 }
                 int res;
                 if (!data.taskRemoved) {
@@ -3490,6 +3512,7 @@
             try {
                 if (ri.mData != null) {
                     ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
+                    ri.mData.prepareToEnterProcess();
                 }
                 if (DEBUG_RESULTS) Slog.v(TAG,
                         "Delivering result to activity " + r + " : " + ri);
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index ca9fabc..b3046b5 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -549,7 +549,7 @@
         Bundle bundle = new Bundle();
         RectF tempBounds = new RectF();
         Matrix tempMatrix = new Matrix();
-        for (int i = 0; i < mSharedElementNames.size(); i++) {
+        for (int i = 0; i < mSharedElements.size(); i++) {
             View sharedElement = mSharedElements.get(i);
             String name = mSharedElementNames.get(i);
             captureSharedElementState(sharedElement, name, bundle, tempMatrix, tempBounds);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 1cb0fd4..f18507e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -61,7 +61,10 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Display;
+
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
+
 import dalvik.system.VMRuntime;
 
 import java.lang.ref.WeakReference;
@@ -74,13 +77,20 @@
     private final static boolean DEBUG = false;
     private final static boolean DEBUG_ICONS = false;
 
-    UserManager mUserManager;
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private UserManager mUserManager;
+    @GuardedBy("mLock")
+    private PackageInstaller mInstaller;
 
     UserManager getUserManager() {
-        if (mUserManager == null) {
-            mUserManager = UserManager.get(mContext);
+        synchronized (mLock) {
+            if (mUserManager == null) {
+                mUserManager = UserManager.get(mContext);
+            }
+            return mUserManager;
         }
-        return mUserManager;
     }
 
     @Override
@@ -1543,12 +1553,17 @@
     }
 
     @Override
-    public PackageInstaller getInstaller() {
-        try {
-            return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getPackageName(),
-                    mContext.getUserId());
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+    public PackageInstaller getPackageInstaller() {
+        synchronized (mLock) {
+            if (mInstaller == null) {
+                try {
+                    mInstaller = new PackageInstaller(this, mPM.getPackageInstaller(),
+                            mContext.getPackageName(), mContext.getUserId());
+                } catch (RemoteException e) {
+                    throw e.rethrowAsRuntimeException();
+                }
+            }
+            return mInstaller;
         }
     }
 
@@ -1568,7 +1583,8 @@
     public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
             int flags) {
         try {
-            mPM.addCrossProfileIntentFilter(filter, sourceUserId, targetUserId, flags);
+            mPM.addCrossProfileIntentFilter(filter, mContext.getOpPackageName(),
+                    mContext.getUserId(), sourceUserId, targetUserId, flags);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1592,7 +1608,8 @@
     @Override
     public void clearCrossProfileIntentFilters(int sourceUserId) {
         try {
-            mPM.clearCrossProfileIntentFilters(sourceUserId);
+            mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName(),
+                    mContext.getUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1606,11 +1623,11 @@
             return new BitmapDrawable(getUserManager().getUserIcon(itemInfo.showUserIcon));
         }
         Drawable dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo);
-        if (dr != null) {
-            dr = getUserManager().getBadgedDrawableForUser(dr,
-                    new UserHandle(mContext.getUserId()));
+        if (dr == null) {
+            dr = getDefaultActivityIcon();
         }
-        return dr;
+        return getUserManager().getBadgedDrawableForUser(dr,
+                new UserHandle(mContext.getUserId()));
     }
 
     private static class LegacyPackageInstallObserver extends PackageInstallObserver {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 0b4510fe..e9d4bd9 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -666,6 +666,15 @@
             reply.writeNoException();
             return true;
         }
+
+        case ENTER_ANIMATION_COMPLETE_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            IBinder token = data.readStrongBinder();
+            scheduleEnterAnimationComplete(token);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -1342,4 +1351,13 @@
         mRemote.transact(BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
         data.recycle();
     }
+
+    @Override
+    public void scheduleEnterAnimationComplete(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(ENTER_ANIMATION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
 }
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index a74fbdf..f4eb558 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -117,10 +117,16 @@
         setTransitionAlpha(mTransitioningViews, 1);
         setTransitionAlpha(mSharedElements, 1);
         mIsHidden = true;
+        if (getDecor() != null) {
+            getDecor().suppressLayout(false);
+        }
         clearState();
     }
 
     private void sharedElementExitBack() {
+        if (getDecor() != null) {
+            getDecor().suppressLayout(true);
+        }
         if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) {
             startTransition(new Runnable() {
                 public void run() {
@@ -136,17 +142,6 @@
         Transition transition = getSharedElementExitTransition();
         final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
                 mSharedElementNames);
-        transition.addListener(new Transition.TransitionListenerAdapter() {
-            @Override
-            public void onTransitionEnd(Transition transition) {
-                transition.removeListener(this);
-                int count = mSharedElements.size();
-                for (int i = 0; i < count; i++) {
-                    View sharedElement = mSharedElements.get(i);
-                    ((ViewGroup)sharedElement.getParent()).suppressLayout(true);
-                }
-            }
-        });
         getDecor().getViewTreeObserver()
                 .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                     @Override
@@ -171,6 +166,9 @@
     public void startExit() {
         if (!mIsExitStarted) {
             mIsExitStarted = true;
+            if (getDecor() != null) {
+                getDecor().suppressLayout(true);
+            }
             startTransition(new Runnable() {
                 @Override
                 public void run() {
@@ -183,6 +181,9 @@
     public void startExit(int resultCode, Intent data) {
         if (!mIsExitStarted) {
             mIsExitStarted = true;
+            if (getDecor() != null) {
+                getDecor().suppressLayout(true);
+            }
             mHandler = new Handler() {
                 @Override
                 public void handleMessage(Message msg) {
@@ -221,6 +222,8 @@
         if (transition != null) {
             TransitionManager.beginDelayedTransition(getDecor(), transition);
             mTransitioningViews.get(0).invalidate();
+        } else {
+            transitionStarted();
         }
     }
 
@@ -307,6 +310,8 @@
         if (transition != null) {
             TransitionManager.beginDelayedTransition(getDecor(), transition);
             getDecor().invalidate();
+        } else {
+            transitionStarted();
         }
     }
 
@@ -352,6 +357,9 @@
                 mExitNotified = true;
                 mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
                 mResultReceiver = null; // done talking
+                if (getDecor() != null) {
+                    getDecor().suppressLayout(false);
+                }
                 finishIfNecessary();
             }
         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index cc13a3b..5347f03 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -332,7 +332,7 @@
 
     public IBinder newUriPermissionOwner(String name) throws RemoteException;
     public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
-            Uri uri, int mode, int userId) throws RemoteException;
+            Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;
     public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
             int mode, int userId) throws RemoteException;
 
@@ -448,6 +448,7 @@
     public void mediaResourcesReleased(IBinder token) throws RemoteException;
 
     public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException;
+    public void notifyEnterAnimationComplete(IBinder token) throws RemoteException;
 
     /*
      * Private non-Binder interfaces
@@ -758,4 +759,5 @@
     int MEDIA_RESOURCES_RELEASED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+227;
     int NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+228;
     int START_ACTIVITY_FROM_RECENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 229;
+    int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 18faf0e..4a1fda4 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -147,6 +147,7 @@
     void updateTimePrefs(boolean is24Hour) throws RemoteException;
     void scheduleStopMediaPlaying(IBinder token) throws RemoteException;
     void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean enabled) throws RemoteException;
+    void scheduleEnterAnimationComplete(IBinder token) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
 
@@ -203,4 +204,5 @@
     int UPDATE_TIME_PREFS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51;
     int STOP_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52;
     int BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53;
+    int ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54;
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a193a34..76cf29a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.app.Activity;
 import android.content.AbstractRestrictionsProvider;
 import android.content.ComponentName;
@@ -272,6 +273,16 @@
         = "android.app.extra.deviceAdminPackageDownloadLocation";
 
     /**
+     * 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_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
+     *
+     * <p>Use in an Nfc record with {@link #PROVISIONING_NFC_MIME_TYPE} that starts device owner
+     * provisioning via an Nfc bump.
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER
+        = "android.app.extra.deviceAdminPackageDownloadCookieHeader";
+
+    /**
      * A String extra holding the SHA-1 checksum of the file at download location specified in
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_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
@@ -301,6 +312,7 @@
      * <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>
      * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} (convert to String), optional</li>
      * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}, optional</li>
@@ -2083,7 +2095,6 @@
 
     /**
      * @hide
-     * @SystemApi
      * Sets the given component as an active admin and registers the package as the profile
      * owner for this user. The package must already be installed and there shouldn't be
      * an existing profile owner registered for this user. Also, this method must be called
@@ -2097,6 +2108,7 @@
      * @throws IllegalArgumentException if packageName is null, the package isn't installed, or
      *         the user has already been set up.
      */
+    @SystemApi
     public boolean setActiveProfileOwner(ComponentName admin, String ownerName)
             throws IllegalArgumentException {
         if (mService != null) {
@@ -2390,8 +2402,9 @@
     }
 
     /**
-     * Called by a profile owner to remove the cross-profile intent filters from the managed profile
-     * and from the parent.
+     * Called by a profile owner to remove the cross-profile intent filters that go from the
+     * managed profile to the parent, or from the parent to the managed profile.
+     * Only removes those that have been set by the profile owner.
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      */
     public void clearCrossProfileIntentFilters(ComponentName admin) {
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index d6345f3..0d41be2 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -29,11 +29,13 @@
      * Reports an event to the UsageStatsManager.
      *
      * @param component The component for which this event ocurred.
+     * @param userId The user id to which the component belongs to.
      * @param timeStamp The time at which this event ocurred.
      * @param eventType The event that occured. Valid values can be found at
      * {@link android.app.usage.UsageStats.Event}
      */
-    public abstract void reportEvent(ComponentName component, long timeStamp, int eventType);
+    public abstract void reportEvent(ComponentName component, int userId,
+            long timeStamp, int eventType);
 
     /**
      * Prepares the UsageStatsService for shutdown.
diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.aidl
similarity index 82%
rename from core/java/android/service/dreams/IDozeHardware.aidl
rename to core/java/android/bluetooth/BluetoothActivityEnergyInfo.aidl
index f5a657b..60cbf9f 100644
--- a/core/java/android/service/dreams/IDozeHardware.aidl
+++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.aidl
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.dreams;
+package android.bluetooth;
 
-/**
- * @hide
- */
-interface IDozeHardware {
-    byte[] sendMessage(String msg, in byte[] arg);
-}
+parcelable BluetoothActivityEnergyInfo;
diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
new file mode 100644
index 0000000..ce87329
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Record of energy and activity information from controller and
+ * underlying bt stack state.Timestamp the record with system
+ * time
+ * @hide
+ */
+public final class BluetoothActivityEnergyInfo implements Parcelable {
+    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) {
+        mBluetoothStackState = stackState;
+        mControllerTxTimeMs = txTime;
+        mControllerRxTimeMs = rxTime;
+        mControllerIdleTimeMs = idleTime;
+        mControllerEnergyUsed = energyUsed;
+        timestamp = System.currentTimeMillis();
+    }
+
+    @Override
+    public String toString() {
+        return "BluetoothActivityEnergyInfo{"
+            + " timestamp=" + timestamp
+            + " mBluetoothStackState=" + mBluetoothStackState
+            + " mControllerTxTimeMs=" + mControllerTxTimeMs
+            + " mControllerRxTimeMs=" + mControllerRxTimeMs
+            + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
+            + " mControllerEnergyUsed=" + mControllerEnergyUsed
+            + " }";
+    }
+
+    public static final Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
+            new Parcelable.Creator<BluetoothActivityEnergyInfo>() {
+        public BluetoothActivityEnergyInfo createFromParcel(Parcel in) {
+            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);
+        }
+        public BluetoothActivityEnergyInfo[] newArray(int size) {
+            return new BluetoothActivityEnergyInfo[size];
+        }
+    };
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mBluetoothStackState);
+        out.writeInt(mControllerTxTimeMs);
+        out.writeInt(mControllerRxTimeMs);
+        out.writeInt(mControllerIdleTimeMs);
+        out.writeInt(mControllerEnergyUsed);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * @return bt stack reported state
+     */
+    public int getBluetoothStackState() {
+        return mBluetoothStackState;
+    }
+
+    /**
+     * @return tx time in ms
+     */
+    public int getControllerTxTimeMillis() {
+        return mControllerTxTimeMs;
+    }
+
+    /**
+     * @return rx time in ms
+     */
+    public int getControllerRxTimeMillis() {
+        return mControllerRxTimeMs;
+    }
+
+    /**
+     * @return idle time in ms
+     */
+    public int getControllerIdleTimeMillis() {
+        return mControllerIdleTimeMs;
+    }
+
+    /**
+     * product of current(mA), voltage(V) and time(ms)
+     * @return energy used
+     */
+    public int getControllerEnergyUsed() {
+        return mControllerEnergyUsed;
+    }
+    /**
+     * @return timestamp(wall clock) of record creation
+     */
+    public long getTimeStamp() {
+        return timestamp;
+    }
+
+    /**
+     * @return if the record is valid
+     */
+    public boolean isValid() {
+        return ((getControllerTxTimeMillis() !=0) ||
+                (getControllerRxTimeMillis() !=0) ||
+                (getControllerIdleTimeMillis() !=0));
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index faf8645..42b8dbf 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -21,6 +21,8 @@
 import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.bluetooth.le.BluetoothLeScanner;
 import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanRecord;
 import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanSettings;
 import android.content.Context;
@@ -354,41 +356,31 @@
     /** The profile is in disconnecting state */
     public static final int STATE_DISCONNECTING = 3;
 
-    /** States for Bluetooth LE advertising */
-    /** @hide */
-    public static final int STATE_ADVERTISE_STARTING = 0;
-    /** @hide */
-    public static final int STATE_ADVERTISE_STARTED = 1;
-    /** @hide */
-    public static final int STATE_ADVERTISE_STOPPING = 2;
-    /** @hide */
-    public static final int STATE_ADVERTISE_STOPPED = 3;
-    /**
-     * Force stopping advertising without callback in case the advertising app dies.
-     * @hide
-     */
-    public static final int STATE_ADVERTISE_FORCE_STOPPING = 4;
-
     /** @hide */
     public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
 
-    /** @hide */
-    public static final int ADVERTISE_CALLBACK_SUCCESS = 0;
-
     private static final int ADDRESS_LENGTH = 17;
 
+    private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30;
+    /** @hide */
+    public static final int ACTIVITY_ENERGY_INFO_CACHED = 0;
+    /** @hide */
+    public static final int ACTIVITY_ENERGY_INFO_REFRESHED = 1;
+
     /**
      * Lazily initialized singleton. Guaranteed final after first object
      * constructed.
      */
     private static BluetoothAdapter sAdapter;
 
+    private static BluetoothLeScanner sBluetoothLeScanner;
+    private static BluetoothLeAdvertiser sBluetoothLeAdvertiser;
+
     private final IBluetoothManager mManagerService;
     private IBluetooth mService;
 
-    private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients;
-    private final Handler mHandler;  // Handler to post the advertise callback to run on main thread.
     private final Object mLock = new Object();
+    private final Map<LeScanCallback, ScanCallback> mLeScanClients;
 
     /**
      * Get a handle to the default local Bluetooth adapter.
@@ -423,8 +415,7 @@
             mService = managerService.registerAdapter(mManagerCallback);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         mManagerService = managerService;
-        mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
-        mHandler = new Handler(Looper.getMainLooper());
+        mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
     }
 
     /**
@@ -463,19 +454,40 @@
     }
 
     /**
-     * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations.
+     * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations, or
+     * null if Bluetooth LE Advertising is not support on this device.
+     * <p>
+     * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported
+     * on this device before calling this method.
      */
     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
-        // TODO: Return null if this feature is not supported by hardware.
-        return new BluetoothLeAdvertiser(mManagerService);
+        if (getState() != STATE_ON) {
+            return null;
+        }
+        if (!isMultipleAdvertisementSupported()) {
+            return null;
+        }
+        synchronized(mLock) {
+            if (sBluetoothLeAdvertiser == null) {
+                sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
+            }
+        }
+        return sBluetoothLeAdvertiser;
     }
 
     /**
      * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
      */
     public BluetoothLeScanner getBluetoothLeScanner() {
-        // TODO: Return null if BLE scan is not supported by hardware.
-        return new BluetoothLeScanner(mManagerService);
+        if (getState() != STATE_ON) {
+            return null;
+        }
+        synchronized(mLock) {
+            if (sBluetoothLeScanner == null) {
+                sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
+            }
+        }
+        return sBluetoothLeScanner;
     }
 
     /**
@@ -935,6 +947,43 @@
     }
 
     /**
+     * Return the record of {@link BluetoothActivityEnergyInfo} object that
+     * has the activity and energy info. This can be used to ascertain what
+     * the controller has been up to, since the last sample.
+     * @param updateType Type of info, cached vs refreshed.
+     *
+     * @return a record with {@link BluetoothActivityEnergyInfo} or null if
+     * report is unavailable or unsupported
+     * @hide
+     */
+    public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
+        if (getState() != STATE_ON) return null;
+        try {
+            BluetoothActivityEnergyInfo record;
+            if (!mService.isActivityAndEnergyReportingSupported()) {
+                return null;
+            }
+            synchronized(this) {
+                if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) {
+                    mService.getActivityEnergyInfoFromController();
+                    wait(CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS);
+                }
+                record = mService.reportActivityInfo();
+                if (record.isValid()) {
+                    return record;
+                } else {
+                    return null;
+                }
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
+        }
+        return null;
+    }
+
+    /**
      * Return the set of {@link BluetoothDevice} objects that are bonded
      * (paired) to the local adapter.
      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
@@ -1600,13 +1649,17 @@
      *             instead.
      */
     @Deprecated
-    public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
+    public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
         if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
-
         if (callback == null) {
             if (DBG) Log.e(TAG, "startLeScan: null callback");
             return false;
         }
+        BluetoothLeScanner scanner = getBluetoothLeScanner();
+        if (scanner == null) {
+            if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
+            return false;
+        }
 
         synchronized(mLeScanClients) {
             if (mLeScanClients.containsKey(callback)) {
@@ -1621,13 +1674,50 @@
                     return false;
                 }
 
-                UUID uuid = UUID.randomUUID();
-                GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
-                iGatt.registerClient(new ParcelUuid(uuid), wrapper);
-                if (wrapper.scanStarted()) {
-                    mLeScanClients.put(callback, wrapper);
-                    return true;
+                ScanCallback scanCallback = new ScanCallback() {
+                    @Override
+                    public void onScanResult(int callbackType, ScanResult result) {
+                        if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
+                            // Should not happen.
+                            Log.e(TAG, "LE Scan has already started");
+                            return;
+                        }
+                        ScanRecord scanRecord = result.getScanRecord();
+                        if (scanRecord == null) {
+                            return;
+                        }
+                        if (serviceUuids != null) {
+                            List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
+                            for (UUID uuid : serviceUuids) {
+                                uuids.add(new ParcelUuid(uuid));
+                            }
+                            List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
+                            if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) {
+                                if (DBG) Log.d(TAG, "uuids does not match");
+                                return;
+                            }
+                        }
+                        callback.onLeScan(result.getDevice(), result.getRssi(),
+                                scanRecord.getBytes());
+                    }
+                };
+                ScanSettings settings = new ScanSettings.Builder()
+                    .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
+                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+
+                List<ScanFilter> filters = new ArrayList<ScanFilter>();
+                if (serviceUuids != null && serviceUuids.length > 0) {
+                    // Note scan filter does not support matching an UUID array so we put one
+                    // UUID to hardware and match the whole array in callback.
+                    ScanFilter filter = new ScanFilter.Builder().setServiceUuid(
+                            new ParcelUuid(serviceUuids[0])).build();
+                    filters.add(filter);
                 }
+                scanner.startScan(filters, settings, scanCallback);
+
+                mLeScanClients.put(callback, scanCallback);
+                return true;
+
             } catch (RemoteException e) {
                 Log.e(TAG,"",e);
             }
@@ -1647,264 +1737,17 @@
     @Deprecated
     public void stopLeScan(LeScanCallback callback) {
         if (DBG) Log.d(TAG, "stopLeScan()");
-        GattCallbackWrapper wrapper;
-        synchronized(mLeScanClients) {
-            wrapper = mLeScanClients.remove(callback);
-            if (wrapper == null) return;
+        BluetoothLeScanner scanner = getBluetoothLeScanner();
+        if (scanner == null) {
+            return;
         }
-        wrapper.stopLeScan();
-    }
-
-    /**
-     * Bluetooth GATT interface callbacks
-     */
-    private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub {
-        private static final int LE_CALLBACK_REG_TIMEOUT = 2000;
-        private static final int LE_CALLBACK_REG_WAIT_COUNT = 5;
-
-        private final LeScanCallback mLeScanCb;
-
-        // mLeHandle 0: not registered
-        //           -1: scan stopped
-        //           >0: registered and scan started
-        private int mLeHandle;
-        private final UUID[] mScanFilter;
-        private WeakReference<BluetoothAdapter> mBluetoothAdapter;
-
-        public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter,
-                                   LeScanCallback leScanCb, UUID[] uuid) {
-            mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter);
-            mLeScanCb = leScanCb;
-            mScanFilter = uuid;
-            mLeHandle = 0;
-        }
-
-        public boolean scanStarted() {
-            return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT);
-        }
-
-        private boolean waitForRegisteration(int maxWaitCount) {
-            boolean started = false;
-            synchronized(this) {
-                if (mLeHandle == -1) return false;
-                int count = 0;
-                // wait for callback registration and LE scan to start
-                while (mLeHandle == 0 && count < maxWaitCount) {
-                    try {
-                        wait(LE_CALLBACK_REG_TIMEOUT);
-                    } catch (InterruptedException e) {
-                        Log.e(TAG, "Callback reg wait interrupted: " + e);
-                    }
-                    count++;
-                }
-                started = (mLeHandle > 0);
+        synchronized (mLeScanClients) {
+            ScanCallback scanCallback = mLeScanClients.remove(callback);
+            if (scanCallback == null) {
+                if (DBG) Log.d(TAG, "scan not started yet");
+                return;
             }
-            return started;
-        }
-
-        public void stopLeScan() {
-            synchronized(this) {
-                if (mLeHandle <= 0) {
-                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
-                    return;
-                }
-                BluetoothAdapter adapter = mBluetoothAdapter.get();
-                if (adapter != null) {
-                    try {
-                        IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt();
-                        iGatt.stopScan(mLeHandle, false);
-                        iGatt.unregisterClient(mLeHandle);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Failed to stop scan and unregister" + e);
-                    }
-                } else {
-                    Log.e(TAG, "stopLeScan, BluetoothAdapter is null");
-                }
-                mLeHandle = -1;
-                notifyAll();
-            }
-        }
-
-        /**
-         * Application interface registered - app is ready to go
-         */
-        public void onClientRegistered(int status, int clientIf) {
-            if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status +
-                           " clientIf=" + clientIf);
-            synchronized(this) {
-                if (mLeHandle == -1) {
-                    if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled");
-                }
-
-                if (status == BluetoothGatt.GATT_SUCCESS) {
-                    mLeHandle = clientIf;
-                    IBluetoothGatt iGatt = null;
-                    try {
-                        BluetoothAdapter adapter = mBluetoothAdapter.get();
-                        if (adapter != null) {
-                            iGatt = adapter.getBluetoothManager().getBluetoothGatt();
-                            if (mScanFilter == null) {
-                                iGatt.startScan(mLeHandle, false);
-                            } else {
-                                ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length];
-                                for(int i = 0; i != uuids.length; ++i) {
-                                    uuids[i] = new ParcelUuid(mScanFilter[i]);
-                                }
-                                iGatt.startScanWithUuids(mLeHandle, false, uuids);
-                            }
-                        } else {
-                            Log.e(TAG, "onClientRegistered, BluetoothAdapter null");
-                            mLeHandle = -1;
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "fail to start le scan: " + e);
-                        mLeHandle = -1;
-                    }
-                    if (mLeHandle == -1) {
-                        // registration succeeded but start scan or advertise failed
-                        if (iGatt != null) {
-                            try {
-                                iGatt.unregisterClient(mLeHandle);
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "fail to unregister callback: " + mLeHandle +
-                                      " error: " + e);
-                            }
-                        }
-                    }
-                } else {
-                    // registration failed
-                    mLeHandle = -1;
-                }
-                notifyAll();
-            }
-        }
-
-        public void onClientConnectionState(int status, int clientIf,
-                                            boolean connected, String address) {
-            // no op
-        }
-
-        /**
-         * Callback reporting an LE scan result.
-         * @hide
-         */
-        public void onScanResult(String address, int rssi, byte[] advData) {
-            if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
-
-            // Check null in case the scan has been stopped
-            synchronized(this) {
-                if (mLeHandle <= 0) return;
-            }
-            try {
-                BluetoothAdapter adapter = mBluetoothAdapter.get();
-                if (adapter == null) {
-                    Log.d(TAG, "onScanResult, BluetoothAdapter null");
-                    return;
-                }
-                mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData);
-            } catch (Exception ex) {
-                Log.w(TAG, "Unhandled exception: " + ex);
-            }
-        }
-
-        public void onGetService(String address, int srvcType,
-                                 int srvcInstId, ParcelUuid srvcUuid) {
-            // no op
-        }
-
-        public void onGetIncludedService(String address, int srvcType,
-                                         int srvcInstId, ParcelUuid srvcUuid,
-                                         int inclSrvcType, int inclSrvcInstId,
-                                         ParcelUuid inclSrvcUuid) {
-            // no op
-        }
-
-        public void onGetCharacteristic(String address, int srvcType,
-                                        int srvcInstId, ParcelUuid srvcUuid,
-                                        int charInstId, ParcelUuid charUuid,
-                                        int charProps) {
-            // no op
-        }
-
-        public void onGetDescriptor(String address, int srvcType,
-                                    int srvcInstId, ParcelUuid srvcUuid,
-                                    int charInstId, ParcelUuid charUuid,
-                                    int descInstId, ParcelUuid descUuid) {
-            // no op
-        }
-
-        public void onSearchComplete(String address, int status) {
-            // no op
-        }
-
-        public void onCharacteristicRead(String address, int status, int srvcType,
-                                         int srvcInstId, ParcelUuid srvcUuid,
-                                         int charInstId, ParcelUuid charUuid, byte[] value) {
-            // no op
-        }
-
-        public void onCharacteristicWrite(String address, int status, int srvcType,
-                                          int srvcInstId, ParcelUuid srvcUuid,
-                                          int charInstId, ParcelUuid charUuid) {
-            // no op
-        }
-
-        public void onNotify(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             byte[] value) {
-            // no op
-        }
-
-        public void onDescriptorRead(String address, int status, int srvcType,
-                                     int srvcInstId, ParcelUuid srvcUuid,
-                                     int charInstId, ParcelUuid charUuid,
-                                     int descInstId, ParcelUuid descrUuid, byte[] value) {
-            // no op
-        }
-
-        public void onDescriptorWrite(String address, int status, int srvcType,
-                                      int srvcInstId, ParcelUuid srvcUuid,
-                                      int charInstId, ParcelUuid charUuid,
-                                      int descInstId, ParcelUuid descrUuid) {
-            // no op
-        }
-
-        public void onExecuteWrite(String address, int status) {
-            // no op
-        }
-
-        public void onReadRemoteRssi(String address, int rssi, int status) {
-            // no op
-        }
-
-        public void onAdvertiseStateChange(int advertiseState, int status) {
-        }
-
-        @Override
-        public void onMultiAdvertiseCallback(int status) {
-            // no op
-        }
-
-        @Override
-        public void onConfigureMTU(String address, int mtu, int status) {
-            // no op
-        }
-
-        @Override
-        public void onConnectionCongested(String address, boolean congested) {
-            // no op
-        }
-
-        @Override
-        public void onBatchScanResults(List<ScanResult> results) {
-            // no op
-        }
-
-        @Override
-        public void onFoundOrLost(boolean onFound, String address,int rssi,
-                byte[] advData) {
-            // no op
+            scanner.stopScan(scanCallback);
         }
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 27f2011..1fe43ec 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -491,6 +491,7 @@
                         mService.readDescriptor(mClientIf, address,
                             srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
                             descrInstId, descrUuid, AUTHENTICATION_MITM);
+                        return;
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
                     }
@@ -544,6 +545,7 @@
                             srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
                             descrInstId, descrUuid, characteristic.getWriteType(),
                             AUTHENTICATION_MITM, descriptor.getValue());
+                        return;
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
                     }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index d334b91..ca55803 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -18,6 +18,7 @@
 
 import android.bluetooth.IBluetoothCallback;
 import android.bluetooth.IBluetoothStateChangeCallback;
+import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.BluetoothDevice;
 import android.os.ParcelUuid;
 import android.os.ParcelFileDescriptor;
@@ -88,4 +89,7 @@
     boolean isMultiAdvertisementSupported();
     boolean isOffloadedFilteringSupported();
     boolean isOffloadedScanBatchingSupported();
+    boolean isActivityAndEnergyReportingSupported();
+    void getActivityEnergyInfoFromController();
+    BluetoothActivityEnergyInfo reportActivityInfo();
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 533be13..edf823e 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -33,10 +33,8 @@
 interface IBluetoothGatt {
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
 
-    void startScan(in int appIf, in boolean isServer);
-    void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids);
-    void startScanWithFilters(in int appIf, in boolean isServer,
-                              in ScanSettings settings, in List<ScanFilter> filters);
+    void startScan(in int appIf, in boolean isServer, in ScanSettings settings,
+                   in List<ScanFilter> filters);
     void stopScan(in int appIf, in boolean isServer);
     void flushPendingBatchResults(in int appIf, in boolean isServer);
     void startMultiAdvertising(in int appIf,
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index f2e4828..b137eeb 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -25,6 +25,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Advertise data packet container for Bluetooth LE advertising. This represents the data to be
@@ -119,13 +120,44 @@
         return mIncludeDeviceName;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hash(mServiceUuids, mManufacturerId, mManufacturerSpecificData,
+                mServiceDataUuid, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        AdvertiseData other = (AdvertiseData) obj;
+        return Objects.equals(mServiceUuids, other.mServiceUuids) &&
+                mManufacturerId == other.mManufacturerId &&
+                Objects.deepEquals(mManufacturerSpecificData, other.mManufacturerSpecificData) &&
+                Objects.equals(mServiceDataUuid, other.mServiceDataUuid) &&
+                Objects.deepEquals(mServiceData, other.mServiceData) &&
+                        mIncludeDeviceName == other.mIncludeDeviceName &&
+                        mIncludeTxPowerLevel == other.mIncludeTxPowerLevel;
+    }
+
     @Override
     public String toString() {
         return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerId="
                 + mManufacturerId + ", mManufacturerSpecificData="
                 + Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
                 + mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData)
-                + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName=" + "]";
+                + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
+                + mIncludeDeviceName + "]";
     }
 
     @Override
@@ -135,32 +167,23 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        if (mServiceUuids == null) {
-            dest.writeInt(0);
-        } else {
-            dest.writeInt(mServiceUuids.size());
-            dest.writeList(mServiceUuids);
-        }
+        dest.writeList(mServiceUuids);
 
         dest.writeInt(mManufacturerId);
         if (mManufacturerSpecificData == null) {
             dest.writeInt(0);
         } else {
+            dest.writeInt(1);
             dest.writeInt(mManufacturerSpecificData.length);
             dest.writeByteArray(mManufacturerSpecificData);
         }
-
-        if (mServiceDataUuid == null) {
+        dest.writeParcelable(mServiceDataUuid, flags);
+        if (mServiceData == null) {
             dest.writeInt(0);
         } else {
             dest.writeInt(1);
-            dest.writeParcelable(mServiceDataUuid, flags);
-            if (mServiceData == null) {
-                dest.writeInt(0);
-            } else {
-                dest.writeInt(mServiceData.length);
-                dest.writeByteArray(mServiceData);
-            }
+            dest.writeInt(mServiceData.length);
+            dest.writeByteArray(mServiceData);
         }
         dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
         dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0));
@@ -179,29 +202,27 @@
             @Override
                 public AdvertiseData createFromParcel(Parcel in) {
                     Builder builder = new Builder();
-                    if (in.readInt() > 0) {
-                        List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
-                        in.readList(uuids, ParcelUuid.class.getClassLoader());
+                    @SuppressWarnings("unchecked")
+                    List<ParcelUuid> uuids = in.readArrayList(ParcelUuid.class.getClassLoader());
+                    if (uuids != null) {
                         for (ParcelUuid uuid : uuids) {
                             builder.addServiceUuid(uuid);
                         }
                     }
                     int manufacturerId = in.readInt();
-                    int manufacturerDataLength = in.readInt();
-                    if (manufacturerDataLength > 0) {
+                    if (in.readInt() == 1) {
+                        int manufacturerDataLength = in.readInt();
                         byte[] manufacturerData = new byte[manufacturerDataLength];
                         in.readByteArray(manufacturerData);
                         builder.setManufacturerData(manufacturerId, manufacturerData);
                     }
+                    ParcelUuid serviceDataUuid = in.readParcelable(
+                            ParcelUuid.class.getClassLoader());
                     if (in.readInt() == 1) {
-                        ParcelUuid serviceDataUuid = in.readParcelable(
-                                ParcelUuid.class.getClassLoader());
                         int serviceDataLength = in.readInt();
-                        if (serviceDataLength > 0) {
-                            byte[] serviceData = new byte[serviceDataLength];
-                            in.readByteArray(serviceData);
-                            builder.setServiceData(serviceDataUuid, serviceData);
-                        }
+                        byte[] serviceData = new byte[serviceDataLength];
+                        in.readByteArray(serviceData);
+                        builder.setServiceData(serviceDataUuid, serviceData);
                     }
                     builder.setIncludeTxPowerLevel(in.readByte() == 1);
                     builder.setIncludeDeviceName(in.readByte() == 1);
@@ -213,15 +234,9 @@
      * Builder for {@link AdvertiseData}.
      */
     public static final class Builder {
-        private static final int MAX_ADVERTISING_DATA_BYTES = 31;
-        // Each fields need one byte for field length and another byte for field type.
-        private static final int OVERHEAD_BYTES_PER_FIELD = 2;
-        // Flags field will be set by system.
-        private static final int FLAGS_FIELD_BYTES = 3;
-
         @Nullable
         private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
-        private int mManufacturerId;
+        private int mManufacturerId = -1;
         @Nullable
         private byte[] mManufacturerSpecificData;
         @Nullable
@@ -307,7 +322,6 @@
 
         /**
          * Build the {@link AdvertiseData}.
-         *
          */
         public AdvertiseData build() {
             return new AdvertiseData(mServiceUuids,
@@ -315,49 +329,5 @@
                     mServiceData, mManufacturerId, mManufacturerSpecificData,
                     mIncludeTxPowerLevel, mIncludeDeviceName);
         }
-
-        // Compute the size of the advertisement data.
-        private int totalBytes() {
-            int size = FLAGS_FIELD_BYTES; // flags field is always set.
-            if (mServiceUuids != null) {
-                int num16BitUuids = 0;
-                int num32BitUuids = 0;
-                int num128BitUuids = 0;
-                for (ParcelUuid uuid : mServiceUuids) {
-                    if (BluetoothUuid.is16BitUuid(uuid)) {
-                        ++num16BitUuids;
-                    } else if (BluetoothUuid.is32BitUuid(uuid)) {
-                        ++num32BitUuids;
-                    } else {
-                        ++num128BitUuids;
-                    }
-                }
-                // 16 bit service uuids are grouped into one field when doing advertising.
-                if (num16BitUuids != 0) {
-                    size += OVERHEAD_BYTES_PER_FIELD +
-                            num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT;
-                }
-                // 32 bit service uuids are grouped into one field when doing advertising.
-                if (num32BitUuids != 0) {
-                    size += OVERHEAD_BYTES_PER_FIELD +
-                            num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT;
-                }
-                // 128 bit service uuids are grouped into one field when doing advertising.
-                if (num128BitUuids != 0) {
-                    size += OVERHEAD_BYTES_PER_FIELD +
-                            num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
-                }
-            }
-            if (mServiceData != null) {
-                size += OVERHEAD_BYTES_PER_FIELD + mServiceData.length;
-            }
-            if (mManufacturerSpecificData != null) {
-                size += OVERHEAD_BYTES_PER_FIELD + mManufacturerSpecificData.length;
-            }
-            if (mIncludeTxPowerLevel) {
-                size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte.
-            }
-            return size;
-        }
     }
 }
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index fc53afe..93d4349 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothManager;
@@ -49,6 +50,14 @@
 
     private static final String TAG = "BluetoothLeAdvertiser";
 
+    private static final int MAX_ADVERTISING_DATA_BYTES = 31;
+    // Each fields need one byte for field length and another byte for field type.
+    private static final int OVERHEAD_BYTES_PER_FIELD = 2;
+    // Flags field will be set by system.
+    private static final int FLAGS_FIELD_BYTES = 3;
+    private static final int MANUFACTURER_SPECIFIC_DATA_LENGTH = 2;
+    private static final int SERVICE_DATA_UUID_LENGTH = 2;
+
     private final IBluetoothManager mBluetoothManager;
     private final Handler mHandler;
     private BluetoothAdapter mBluetoothAdapter;
@@ -101,6 +110,11 @@
         if (callback == null) {
             throw new IllegalArgumentException("callback cannot be null");
         }
+        if (totalBytes(advertiseData) > MAX_ADVERTISING_DATA_BYTES ||
+                totalBytes(scanResponse) > MAX_ADVERTISING_DATA_BYTES) {
+            postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE);
+            return;
+        }
         if (mLeAdvertisers.containsKey(callback)) {
             postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
             return;
@@ -159,6 +173,62 @@
         }
     }
 
+    // Compute the size of the advertise data.
+    private int totalBytes(AdvertiseData data) {
+        if (data == null) {
+            return 0;
+        }
+        int size = FLAGS_FIELD_BYTES; // flags field is always set.
+        if (data.getServiceUuids() != null) {
+            int num16BitUuids = 0;
+            int num32BitUuids = 0;
+            int num128BitUuids = 0;
+            for (ParcelUuid uuid : data.getServiceUuids()) {
+                if (BluetoothUuid.is16BitUuid(uuid)) {
+                    ++num16BitUuids;
+                } else if (BluetoothUuid.is32BitUuid(uuid)) {
+                    ++num32BitUuids;
+                } else {
+                    ++num128BitUuids;
+                }
+            }
+            // 16 bit service uuids are grouped into one field when doing advertising.
+            if (num16BitUuids != 0) {
+                size += OVERHEAD_BYTES_PER_FIELD +
+                        num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT;
+            }
+            // 32 bit service uuids are grouped into one field when doing advertising.
+            if (num32BitUuids != 0) {
+                size += OVERHEAD_BYTES_PER_FIELD +
+                        num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT;
+            }
+            // 128 bit service uuids are grouped into one field when doing advertising.
+            if (num128BitUuids != 0) {
+                size += OVERHEAD_BYTES_PER_FIELD +
+                        num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
+            }
+        }
+        if (data.getServiceDataUuid() != null) {
+            size += OVERHEAD_BYTES_PER_FIELD + SERVICE_DATA_UUID_LENGTH
+                    + byteLength(data.getServiceData());
+        }
+        if (data.getManufacturerId() > 0) {
+            size += OVERHEAD_BYTES_PER_FIELD + MANUFACTURER_SPECIFIC_DATA_LENGTH +
+                    byteLength(data.getManufacturerSpecificData());
+        }
+        if (data.getIncludeTxPowerLevel()) {
+            size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte.
+        }
+        if (data.getIncludeDeviceName() && mBluetoothAdapter.getName() != null) {
+            size += OVERHEAD_BYTES_PER_FIELD + mBluetoothAdapter.getName().length();
+        }
+        return size;
+    }
+
+    private int byteLength(byte[] array) {
+        return array == null ? 0 : array.length;
+    }
+
     /**
      * Bluetooth GATT interface callbacks for advertising.
      */
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 980f717..8e7d400 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -151,6 +151,7 @@
         synchronized (mLeScanClients) {
             BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback);
             if (wrapper == null) {
+                if (DBG) Log.d(TAG, "could not find callback wrapper");
                 return;
             }
             wrapper.stopLeScan();
@@ -266,7 +267,7 @@
                 if (status == BluetoothGatt.GATT_SUCCESS) {
                     mClientIf = clientIf;
                     try {
-                        mBluetoothGatt.startScanWithFilters(mClientIf, false, mSettings, mFilters);
+                        mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters);
                     } catch (RemoteException e) {
                         Log.e(TAG, "fail to start le scan: " + e);
                         mClientIf = -1;
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 0ae11b0..2ce18b0 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -107,7 +107,7 @@
                 dest.writeParcelable(mServiceUuidMask, flags);
             }
         }
-        dest.writeInt(mServiceDataUuid == null? 0 : 1);
+        dest.writeInt(mServiceDataUuid == null ? 0 : 1);
         if (mServiceDataUuid != null) {
             dest.writeParcelable(mServiceDataUuid, flags);
             dest.writeInt(mServiceData == null ? 0 : mServiceData.length);
@@ -235,6 +235,14 @@
     }
 
     /**
+     * @hide
+     */
+    @Nullable
+    public ParcelUuid getServiceDataUuid() {
+        return mServiceDataUuid;
+    }
+
+    /**
      * Returns the manufacturer id. -1 if the manufacturer filter is not set.
      */
     public int getManufacturerId() {
@@ -287,15 +295,21 @@
         }
 
         // Service data match
-        if (mServiceData != null &&
-                !matchesPartialData(mServiceData, mServiceDataMask, scanRecord.getServiceData())) {
-            return false;
+        if (mServiceData != null) {
+            if (!Objects.equals(mServiceDataUuid, scanRecord.getServiceDataUuid()) ||
+                    !matchesPartialData(mServiceData, mServiceDataMask,
+                            scanRecord.getServiceData())) {
+                return false;
+            }
         }
 
         // Manufacturer data match.
-        if (mManufacturerData != null && !matchesPartialData(mManufacturerData,
-                mManufacturerDataMask, scanRecord.getManufacturerSpecificData())) {
-            return false;
+        if (mManufacturerData != null) {
+            if (mManufacturerId != scanRecord.getManufacturerId() ||
+                    !matchesPartialData(mManufacturerData,
+                            mManufacturerDataMask, scanRecord.getManufacturerSpecificData())) {
+                return false;
+            }
         }
         // All filters match.
         return true;
@@ -353,7 +367,8 @@
     public String toString() {
         return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress="
                 + mDeviceAddress
-                + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask + ", mServiceData="
+                + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask
+                + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) + ", mServiceData="
                 + Arrays.toString(mServiceData) + ", mServiceDataMask="
                 + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId
                 + ", mManufacturerData=" + Arrays.toString(mManufacturerData)
@@ -363,7 +378,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId, mManufacturerData,
-                mManufacturerDataMask, mServiceData, mServiceDataMask,
+                mManufacturerDataMask, mServiceDataUuid, mServiceData, mServiceDataMask,
                 mServiceUuid, mServiceUuidMask);
     }
 
@@ -381,6 +396,7 @@
                         mManufacturerId == other.mManufacturerId &&
                 Objects.deepEquals(mManufacturerData, other.mManufacturerData) &&
                 Objects.deepEquals(mManufacturerDataMask, other.mManufacturerDataMask) &&
+                Objects.deepEquals(mServiceDataUuid, other.mServiceDataUuid) &&
                 Objects.deepEquals(mServiceData, other.mServiceData) &&
                 Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) &&
                 Objects.equals(mServiceUuid, other.mServiceUuid) &&
@@ -498,6 +514,7 @@
                             "size mismatch for service data and service data mask");
                 }
             }
+            mServiceDataUuid = serviceDataUuid;
             mServiceData = serviceData;
             mServiceDataMask = serviceDataMask;
             return this;
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index dd03308..e564c7d 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -225,20 +225,21 @@
                         txPowerLevel = scanRecord[currentPos];
                         break;
                     case DATA_TYPE_SERVICE_DATA:
-                        serviceData = extractBytes(scanRecord, currentPos, dataLength);
-                        // The first two bytes of the service data are service data UUID.
+                        // The first two bytes of the service data are service data UUID in little
+                        // endian. The rest bytes are service data.
                         int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
                         byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
                                 serviceUuidLength);
                         serviceDataUuid = BluetoothUuid.parseUuidFrom(serviceDataUuidBytes);
+                        serviceData = extractBytes(scanRecord, currentPos + 2, dataLength - 2);
                         break;
                     case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
-                        manufacturerSpecificData = extractBytes(scanRecord, currentPos,
-                                dataLength);
                         // The first two bytes of the manufacturer specific data are
                         // manufacturer ids in little endian.
-                        manufacturerId = ((manufacturerSpecificData[1] & 0xFF) << 8) +
-                                (manufacturerSpecificData[0] & 0xFF);
+                        manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
+                                (scanRecord[currentPos] & 0xFF);
+                        manufacturerSpecificData = extractBytes(scanRecord, currentPos + 2,
+                                dataLength - 2);
                         break;
                     default:
                         // Just ignore, we don't handle such data type.
diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java
index 9aee200..a0bdaff 100644
--- a/core/java/android/bluetooth/le/ScanResult.java
+++ b/core/java/android/bluetooth/le/ScanResult.java
@@ -69,7 +69,7 @@
             dest.writeInt(0);
         }
         if (mScanRecord != null) {
-            dest.writeInt(mScanRecord.getBytes().length);
+            dest.writeInt(1);
             dest.writeByteArray(mScanRecord.getBytes());
         } else {
             dest.writeInt(0);
@@ -145,7 +145,7 @@
     @Override
     public String toString() {
         return "ScanResult{" + "mDevice=" + mDevice + ", mScanRecord="
-                + mScanRecord.toString() + ", mRssi=" + mRssi + ", mTimestampNanos="
+                + Objects.toString(mScanRecord) + ", mRssi=" + mRssi + ", mTimestampNanos="
                 + mTimestampNanos + '}';
     }
 
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 2f86d09..b2ee6a8 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -21,38 +21,37 @@
 import android.os.Parcelable;
 
 /**
- * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan}
- * to define the parameters for the scan.
+ * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan} to define the
+ * parameters for the scan.
  */
 public final class ScanSettings implements Parcelable {
     /**
-     * Perform Bluetooth LE scan in low power mode.
-     * This is the default scan mode as it consumes the least power.
+     * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the
+     * least power.
      */
     public static final int SCAN_MODE_LOW_POWER = 0;
 
     /**
-     * Perform Bluetooth LE scan in balanced power mode.
-     * Scan results are returned at a rate that provides a good trade-off between scan
-     * frequency and power consumption.
+     * Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that
+     * provides a good trade-off between scan frequency and power consumption.
      */
     public static final int SCAN_MODE_BALANCED = 1;
 
     /**
-     * Scan using highest duty cycle.
-     * It's recommended to only use this mode when the application is running in the foreground.
+     * Scan using highest duty cycle. It's recommended to only use this mode when the application is
+     * running in the foreground.
      */
     public static final int SCAN_MODE_LOW_LATENCY = 2;
 
     /**
-     * Trigger a callback for every Bluetooth advertisement found that matches the
-     * filter criteria. If no filter is active, all advertisement packets are reported.
+     * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria.
+     * If no filter is active, all advertisement packets are reported.
      */
     public static final int CALLBACK_TYPE_ALL_MATCHES = 1;
 
     /**
-     * A result callback is only triggered for the first advertisement packet received that
-     * matches the filter criteria.
+     * A result callback is only triggered for the first advertisement packet received that matches
+     * the filter criteria.
      */
     public static final int CALLBACK_TYPE_FIRST_MATCH = 2;
 
@@ -63,15 +62,17 @@
     public static final int CALLBACK_TYPE_MATCH_LOST = 4;
 
     /**
-     * Request full scan results which contain the device, rssi, advertising data, scan response
-     * as well as the scan timestamp.
+     * Request full scan results which contain the device, rssi, advertising data, scan response as
+     * well as the scan timestamp.
      */
     public static final int SCAN_RESULT_TYPE_FULL = 0;
 
     /**
      * Request abbreviated scan results which contain the device, rssi and scan timestamp.
-     * <p><b>Note:</b> It is possible for an application to get more scan results than
-     * it asked for, if there are multiple apps using this type.
+     * <p>
+     * <b>Note:</b> It is possible for an application to get more scan results than it asked for, if
+     * there are multiple apps using this type.
+     *
      * @hide
      */
     @SystemApi
@@ -109,11 +110,11 @@
     }
 
     private ScanSettings(int scanMode, int callbackType, int scanResultType,
-            long reportDelaySeconds) {
+            long reportDelayMillis) {
         mScanMode = scanMode;
         mCallbackType = callbackType;
         mScanResultType = scanResultType;
-        mReportDelayMillis = reportDelaySeconds;
+        mReportDelayMillis = reportDelayMillis;
     }
 
     private ScanSettings(Parcel in) {
@@ -184,15 +185,24 @@
          * @throws IllegalArgumentException If the {@code callbackType} is invalid.
          */
         public Builder setCallbackType(int callbackType) {
-            if (callbackType < CALLBACK_TYPE_ALL_MATCHES
-             || callbackType > (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST)
-             || (callbackType & CALLBACK_TYPE_ALL_MATCHES) != CALLBACK_TYPE_ALL_MATCHES) {
+
+            if (!isValidCallbackType(callbackType)) {
                 throw new IllegalArgumentException("invalid callback type - " + callbackType);
             }
             mCallbackType = callbackType;
             return this;
         }
 
+        // Returns true if the callbackType is valid.
+        private boolean isValidCallbackType(int callbackType) {
+            if (callbackType == CALLBACK_TYPE_ALL_MATCHES ||
+                    callbackType == CALLBACK_TYPE_FIRST_MATCH ||
+                    callbackType == CALLBACK_TYPE_MATCH_LOST) {
+                return true;
+            }
+            return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST);
+        }
+
         /**
          * Set scan result type for Bluetooth LE scan.
          *
@@ -215,16 +225,15 @@
 
         /**
          * Set report delay timestamp for Bluetooth LE scan.
-         * @param reportDelayMillis Set to 0 to be notified of results immediately.
-         *                           Values &gt; 0 causes the scan results to be queued
-         *                           up and delivered after the requested delay or when
-         *                           the internal buffers fill up.
-         * @throws IllegalArgumentException If {@code reportDelaySeconds} &lt; 0.
          *
+         * @param reportDelayMillis Set to 0 to be notified of results immediately. Values &gt; 0
+         *            causes the scan results to be queued up and delivered after the requested
+         *            delay or when the internal buffers fill up.
+         * @throws IllegalArgumentException If {@code reportDelayMillis} &lt; 0.
          */
         public Builder setReportDelayMillis(long reportDelayMillis) {
             if (reportDelayMillis < 0) {
-                throw new IllegalArgumentException("reportDelaySeconds must be > 0");
+                throw new IllegalArgumentException("reportDelayMillis must be > 0");
             }
             mReportDelayMillis = reportDelayMillis;
             return this;
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index b44abf9..d19604b 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -810,20 +810,36 @@
         }
     }
 
-    /**
-     * Prepare this {@link ClipData} to leave an app process.
-     *
-     * @hide
-     */
-    public void prepareToLeaveUser(int userId) {
+    /** @hide */
+    public void fixUris(int contentUserHint) {
         final int size = mItems.size();
         for (int i = 0; i < size; i++) {
             final Item item = mItems.get(i);
             if (item.mIntent != null) {
-                item.mIntent.prepareToLeaveUser(userId);
+                item.mIntent.fixUris(contentUserHint);
             }
             if (item.mUri != null) {
-                item.mUri = maybeAddUserId(item.mUri, userId);
+                item.mUri = maybeAddUserId(item.mUri, contentUserHint);
+            }
+        }
+    }
+
+    /**
+     * Only fixing the data field of the intents
+     * @hide
+     */
+    public void fixUrisLight(int contentUserHint) {
+        final int size = mItems.size();
+        for (int i = 0; i < size; i++) {
+            final Item item = mItems.get(i);
+            if (item.mIntent != null) {
+                Uri data = item.mIntent.getData();
+                if (data != null) {
+                    item.mIntent.setData(maybeAddUserId(data, contentUserHint));
+                }
+            }
+            if (item.mUri != null) {
+                item.mUri = maybeAddUserId(item.mUri, contentUserHint);
             }
         }
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3f705ac..f224f40 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.content.pm.ApplicationInfo;
+import android.provider.MediaStore;
 import android.util.ArraySet;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -38,6 +39,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
+import android.os.UserHandle;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
 import android.provider.OpenableColumns;
@@ -1413,6 +1415,21 @@
     public static final String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
 
     /**
+     * Activity Action: Prompt the user to confirm credentials (pin, pattern or password)
+     * for the current user of the device. Launch this activity using
+     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check if the
+     * result is {@link android.app.Activity#RESULT_OK} for a successful response to the
+     * challenge.<p/>
+     * This intent is handled by the system at a high priority and applications cannot intercept
+     * it.<p/>
+     * You can use {@link android.app.KeyguardManager#isKeyguardSecure()} to determine if the user will be
+     * prompted.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL = "android.intent.action.CONFIRM_DEVICE_CREDENTIAL";
+
+
+    /**
      * Specify whether the package should be uninstalled for all users.
      * @hide because these should not be part of normal application flow.
      */
@@ -2682,8 +2699,7 @@
             "android.intent.action.QUICK_CLOCK";
 
     /**
-     * Broadcast Action: This is broadcast when a user action should request the
-     * brightness setting dialog.
+     * Activity Action: Shows the brightness setting dialog.
      * @hide
      */
     public static final String ACTION_SHOW_BRIGHTNESS_DIALOG =
@@ -3161,11 +3177,17 @@
 
     /**
      * A CharSequence dialog title to provide to the user when used with a
-     * {@link #ACTION_CHOOSER}.
+     * {@link #ACTION_CHOOSER} or {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
      */
     public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
 
     /**
+     * A CharSequence description to provide to the user when used with
+     * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
+     */
+    public static final String EXTRA_DETAILS = "android.intent.extra.DETAILS";
+
+    /**
      * A Parcelable[] of {@link Intent} or
      * {@link android.content.pm.LabeledIntent} objects as set with
      * {@link #putExtra(String, Parcelable[])} of additional activities to place
@@ -3938,6 +3960,7 @@
     private Rect mSourceBounds;
     private Intent mSelector;
     private ClipData mClipData;
+    private int mContentUserHint = UserHandle.USER_CURRENT;
 
     // ---------------------------------------------------------------------
 
@@ -3957,6 +3980,7 @@
         this.mPackage = o.mPackage;
         this.mComponent = o.mComponent;
         this.mFlags = o.mFlags;
+        this.mContentUserHint = o.mContentUserHint;
         if (o.mCategories != null) {
             this.mCategories = new ArraySet<String>(o.mCategories);
         }
@@ -4661,6 +4685,11 @@
         return mClipData;
     }
 
+    /** @hide */
+    public int getContentUserHint() {
+        return mContentUserHint;
+    }
+
     /**
      * Sets the ClassLoader that will be used when unmarshalling
      * any Parcelable values from the extras of this Intent.
@@ -5680,6 +5709,16 @@
     }
 
     /**
+     * This is NOT a secure mechanism to identify the user who sent the intent.
+     * When the intent is sent to a different user, it is used to fix uris by adding the userId
+     * who sent the intent.
+     * @hide
+     */
+    public void setContentUserHint(int contentUserHint) {
+        mContentUserHint = contentUserHint;
+    }
+
+    /**
      * Add extended data to the intent.  The name must include a package
      * prefix, for example the app com.android.contacts would use names
      * like "com.android.contacts.ShowAll".
@@ -6732,6 +6771,7 @@
     @FillInFlags
     public int fillIn(Intent other, @FillInFlags int flags) {
         int changes = 0;
+        boolean mayHaveCopiedUris = false;
         if (other.mAction != null
                 && (mAction == null || (flags&FILL_IN_ACTION) != 0)) {
             mAction = other.mAction;
@@ -6743,6 +6783,7 @@
             mData = other.mData;
             mType = other.mType;
             changes |= FILL_IN_DATA;
+            mayHaveCopiedUris = true;
         }
         if (other.mCategories != null
                 && (mCategories == null || (flags&FILL_IN_CATEGORIES) != 0)) {
@@ -6772,6 +6813,7 @@
                 && (mClipData == null || (flags&FILL_IN_CLIP_DATA) != 0)) {
             mClipData = other.mClipData;
             changes |= FILL_IN_CLIP_DATA;
+            mayHaveCopiedUris = true;
         }
         // Component is special: it can -only- be set if explicitly allowed,
         // since otherwise the sender could force the intent somewhere the
@@ -6789,12 +6831,14 @@
         if (mExtras == null) {
             if (other.mExtras != null) {
                 mExtras = new Bundle(other.mExtras);
+                mayHaveCopiedUris = true;
             }
         } else if (other.mExtras != null) {
             try {
                 Bundle newb = new Bundle(other.mExtras);
                 newb.putAll(mExtras);
                 mExtras = newb;
+                mayHaveCopiedUris = true;
             } catch (RuntimeException e) {
                 // Modifying the extras can cause us to unparcel the contents
                 // of the bundle, and if we do this in the system process that
@@ -6804,6 +6848,10 @@
                 Log.w("Intent", "Failure filling in extras", e);
             }
         }
+        if (mayHaveCopiedUris && mContentUserHint == UserHandle.USER_CURRENT
+                && other.mContentUserHint != UserHandle.USER_CURRENT) {
+            mContentUserHint = other.mContentUserHint;
+        }
         return changes;
     }
 
@@ -7031,8 +7079,15 @@
             first = false;
             b.append("(has extras)");
         }
+        if (mContentUserHint != UserHandle.USER_CURRENT) {
+            if (!first) {
+                b.append(' ');
+            }
+            first = false;
+            b.append("u=").append(mContentUserHint);
+        }
         if (mSelector != null) {
-            b.append(" sel={");
+            b.append(" sel=");
             mSelector.toShortString(b, secure, comp, extras, clip);
             b.append("}");
         }
@@ -7209,7 +7264,7 @@
         } else {
             out.writeInt(0);
         }
-
+        out.writeInt(mContentUserHint);
         out.writeBundle(mExtras);
     }
 
@@ -7258,7 +7313,7 @@
         if (in.readInt() != 0) {
             mClipData = new ClipData(in);
         }
-
+        mContentUserHint = in.readInt();
         mExtras = in.readBundle();
     }
 
@@ -7468,39 +7523,50 @@
     }
 
     /**
-     * Prepare this {@link Intent} to be sent to another user
-     *
      * @hide
      */
-    public void prepareToLeaveUser(int userId) {
+    public void prepareToEnterProcess() {
+        if (mContentUserHint != UserHandle.USER_CURRENT) {
+            fixUris(mContentUserHint);
+            mContentUserHint = UserHandle.USER_CURRENT;
+        }
+    }
+
+    /**
+     * @hide
+     */
+     public void fixUris(int contentUserHint) {
         Uri data = getData();
         if (data != null) {
-            mData = maybeAddUserId(data, userId);
-        }
-        if (mSelector != null) {
-            mSelector.prepareToLeaveUser(userId);
+            mData = maybeAddUserId(data, contentUserHint);
         }
         if (mClipData != null) {
-            mClipData.prepareToLeaveUser(userId);
+            mClipData.fixUris(contentUserHint);
         }
         String action = getAction();
         if (ACTION_SEND.equals(action)) {
             final Uri stream = getParcelableExtra(EXTRA_STREAM);
             if (stream != null) {
-                putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId));
+                putExtra(EXTRA_STREAM, maybeAddUserId(stream, contentUserHint));
             }
-        }
-        if (ACTION_SEND_MULTIPLE.equals(action)) {
+        } else if (ACTION_SEND_MULTIPLE.equals(action)) {
             final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
             if (streams != null) {
                 ArrayList<Uri> newStreams = new ArrayList<Uri>();
                 for (int i = 0; i < streams.size(); i++) {
-                    newStreams.add(maybeAddUserId(streams.get(i), userId));
+                    newStreams.add(maybeAddUserId(streams.get(i), contentUserHint));
                 }
                 putParcelableArrayListExtra(EXTRA_STREAM, newStreams);
             }
+        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
+                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
+                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) {
+            final Uri output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
+            if (output != null) {
+                putExtra(MediaStore.EXTRA_OUTPUT, maybeAddUserId(output, contentUserHint));
+            }
         }
-    }
+     }
 
     /**
      * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
@@ -7591,6 +7657,20 @@
                 }
             } catch (ClassCastException e) {
             }
+        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
+                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
+                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) {
+            final Uri output;
+            try {
+                output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
+            } catch (ClassCastException e) {
+                return false;
+            }
+            if (output != null) {
+                setClipData(ClipData.newRawUri("", output));
+                addFlags(FLAG_GRANT_WRITE_URI_PERMISSION|FLAG_GRANT_READ_URI_PERMISSION);
+                return true;
+            }
         }
 
         return false;
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 0acf043..d9005b2 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -35,6 +35,8 @@
     ResolveInfo resolveActivity(in Intent intent, in UserHandle user);
     void startActivityAsUser(in ComponentName component, in Rect sourceBounds,
             in Bundle opts, in UserHandle user);
+    void showAppDetailsAsUser(in ComponentName component, in Rect sourceBounds,
+            in Bundle opts, in UserHandle user);
     boolean isPackageEnabled(String packageName, in UserHandle user);
     boolean isActivityEnabled(in ComponentName component, in UserHandle user);
 }
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 32460c9..0c65034 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -17,7 +17,7 @@
 package android.content.pm;
 
 import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallerObserver;
+import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.InstallSessionInfo;
 import android.content.pm.InstallSessionParams;
@@ -25,13 +25,15 @@
 
 /** {@hide} */
 interface IPackageInstaller {
-    int createSession(String installerPackageName, in InstallSessionParams params, int userId);
+    int createSession(in InstallSessionParams params, String installerPackageName, int userId);
     IPackageInstallerSession openSession(int sessionId);
 
-    List<InstallSessionInfo> getSessions(int userId);
+    InstallSessionInfo getSessionInfo(int sessionId);
+    List<InstallSessionInfo> getAllSessions(int userId);
+    List<InstallSessionInfo> getMySessions(String installerPackageName, int userId);
 
-    void registerObserver(IPackageInstallerObserver observer, int userId);
-    void unregisterObserver(IPackageInstallerObserver observer, int userId);
+    void registerCallback(IPackageInstallerCallback callback, int userId);
+    void unregisterCallback(IPackageInstallerCallback callback);
 
     void uninstall(String packageName, int flags, in IPackageDeleteObserver observer, int userId);
     void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId);
diff --git a/core/java/android/content/pm/IPackageInstallerObserver.aidl b/core/java/android/content/pm/IPackageInstallerCallback.aidl
similarity index 77%
rename from core/java/android/content/pm/IPackageInstallerObserver.aidl
rename to core/java/android/content/pm/IPackageInstallerCallback.aidl
index 85660e4..a31ae54 100644
--- a/core/java/android/content/pm/IPackageInstallerObserver.aidl
+++ b/core/java/android/content/pm/IPackageInstallerCallback.aidl
@@ -16,11 +16,9 @@
 
 package android.content.pm;
 
-import android.content.pm.InstallSessionInfo;
-
 /** {@hide} */
-oneway interface IPackageInstallerObserver {
-    void onSessionCreated(in InstallSessionInfo info);
-    void onSessionProgress(int sessionId, int progress);
+oneway interface IPackageInstallerCallback {
+    void onSessionCreated(int sessionId);
+    void onSessionProgressChanged(int sessionId, float progress);
     void onSessionFinished(int sessionId, boolean success);
 }
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index d6775d4..2fd7ddb 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -21,11 +21,12 @@
 
 /** {@hide} */
 interface IPackageInstallerSession {
-    void setClientProgress(int progress);
-    void addClientProgress(int progress);
+    void setClientProgress(float progress);
+    void addClientProgress(float progress);
 
     ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
 
-    void install(in IPackageInstallObserver2 observer);
-    void destroy();
+    void close();
+    void commit(in IPackageInstallObserver2 observer);
+    void abandon();
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4b339a1..7196372 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -244,13 +244,13 @@
 
     void clearPackagePersistentPreferredActivities(String packageName, int userId);
 
-    void addCrossProfileIntentFilter(in IntentFilter intentFilter, int sourceUserId, int targetUserId,
-            int flags);
+    void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,
+            int ownerUserId, int sourceUserId, int targetUserId, int flags);
 
     void addCrossProfileIntentsForPackage(in String packageName, int sourceUserId,
             int targetUserId);
 
-    void clearCrossProfileIntentFilters(int sourceUserId);
+    void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage, int ownerUserId);
 
     /**
      * Report the set of 'Home' activity candidates, plus (if any) which of them
@@ -397,6 +397,8 @@
      */
     boolean performDexOptIfNeeded(String packageName, String instructionSet);
 
+    void forceDexOpt(String packageName);
+
     /**
      * Update status of external media on the package manager to scan and
      * install packages installed on the external media. Like say the
diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java
index 3336727..a9c574a 100644
--- a/core/java/android/content/pm/InstallSessionInfo.java
+++ b/core/java/android/content/pm/InstallSessionInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.Nullable;
 import android.graphics.Bitmap;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -30,16 +31,18 @@
     /** {@hide} */
     public String installerPackageName;
     /** {@hide} */
-    public int progress;
+    public float progress;
 
     /** {@hide} */
     public int mode;
     /** {@hide} */
-    public String packageName;
+    public long sizeBytes;
     /** {@hide} */
-    public Bitmap icon;
+    public String appPackageName;
     /** {@hide} */
-    public CharSequence title;
+    public Bitmap appIcon;
+    /** {@hide} */
+    public CharSequence appLabel;
 
     /** {@hide} */
     public InstallSessionInfo() {
@@ -49,12 +52,13 @@
     public InstallSessionInfo(Parcel source) {
         sessionId = source.readInt();
         installerPackageName = source.readString();
-        progress = source.readInt();
+        progress = source.readFloat();
 
         mode = source.readInt();
-        packageName = source.readString();
-        icon = source.readParcelable(null);
-        title = source.readString();
+        sizeBytes = source.readLong();
+        appPackageName = source.readString();
+        appIcon = source.readParcelable(null);
+        appLabel = source.readString();
     }
 
     /**
@@ -67,19 +71,19 @@
     /**
      * Return the package name of the app that owns this session.
      */
-    public String getInstallerPackageName() {
+    public @Nullable String getInstallerPackageName() {
         return installerPackageName;
     }
 
     /**
-     * Return current overall progress of this session, between 0 and 100.
+     * Return current overall progress of this session, between 0 and 1.
      * <p>
      * Note that this progress may not directly correspond to the value reported
-     * by {@link PackageInstaller.Session#setProgress(int)}, as the system may
+     * by {@link PackageInstaller.Session#setProgress(float)}, as the system may
      * carve out a portion of the overall progress to represent its own internal
      * installation work.
      */
-    public int getProgress() {
+    public float getProgress() {
         return progress;
     }
 
@@ -87,24 +91,24 @@
      * Return the package name this session is working with. May be {@code null}
      * if unknown.
      */
-    public String getPackageName() {
-        return packageName;
+    public @Nullable String getAppPackageName() {
+        return appPackageName;
     }
 
     /**
      * Return an icon representing the app being installed. May be {@code null}
      * if unavailable.
      */
-    public Bitmap getIcon() {
-        return icon;
+    public @Nullable Bitmap getAppIcon() {
+        return appIcon;
     }
 
     /**
-     * Return a title representing the app being installed. May be {@code null}
+     * Return a label representing the app being installed. May be {@code null}
      * if unavailable.
      */
-    public CharSequence getTitle() {
-        return title;
+    public @Nullable CharSequence getAppLabel() {
+        return appLabel;
     }
 
     @Override
@@ -116,12 +120,13 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(sessionId);
         dest.writeString(installerPackageName);
-        dest.writeInt(progress);
+        dest.writeFloat(progress);
 
         dest.writeInt(mode);
-        dest.writeString(packageName);
-        dest.writeParcelable(icon, flags);
-        dest.writeString(title != null ? title.toString() : null);
+        dest.writeLong(sizeBytes);
+        dest.writeString(appPackageName);
+        dest.writeParcelable(appIcon, flags);
+        dest.writeString(appLabel != null ? appLabel.toString() : null);
     }
 
     public static final Parcelable.Creator<InstallSessionInfo>
diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java
index e039699..3de9863 100644
--- a/core/java/android/content/pm/InstallSessionParams.java
+++ b/core/java/android/content/pm/InstallSessionParams.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.Nullable;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -29,17 +30,25 @@
  */
 public class InstallSessionParams implements Parcelable {
 
-    // TODO: extend to support remaining VerificationParams
-
-    /** {@hide} */
-    public static final int MODE_INVALID = 0;
-    /** {@hide} */
+    /**
+     * Mode for an install session whose staged APKs should fully replace any
+     * existing APKs for the target app.
+     */
     public static final int MODE_FULL_INSTALL = 1;
-    /** {@hide} */
+
+    /**
+     * Mode for an install session that should inherit any existing APKs for the
+     * target app, unless they have been explicitly overridden (based on split
+     * name) by the session. For example, this can be used to add one or more
+     * split APKs to an existing installation.
+     * <p>
+     * If there are no existing APKs for the target app, this behaves like
+     * {@link #MODE_FULL_INSTALL}.
+     */
     public static final int MODE_INHERIT_EXISTING = 2;
 
     /** {@hide} */
-    public int mode = MODE_INVALID;
+    public int mode;
     /** {@hide} */
     public int installFlags;
     /** {@hide} */
@@ -47,15 +56,13 @@
     /** {@hide} */
     public Signature[] signatures;
     /** {@hide} */
-    public long deltaSize = -1;
+    public long sizeBytes = -1;
     /** {@hide} */
-    public int progressMax = 100;
+    public String appPackageName;
     /** {@hide} */
-    public String packageName;
+    public Bitmap appIcon;
     /** {@hide} */
-    public Bitmap icon;
-    /** {@hide} */
-    public CharSequence title;
+    public CharSequence appLabel;
     /** {@hide} */
     public Uri originatingUri;
     /** {@hide} */
@@ -63,7 +70,15 @@
     /** {@hide} */
     public String abiOverride;
 
-    public InstallSessionParams() {
+    /**
+     * Construct parameters for a new package install session.
+     *
+     * @param mode one of {@link #MODE_FULL_INSTALL} or
+     *            {@link #MODE_INHERIT_EXISTING} describing how the session
+     *            should interact with an existing app.
+     */
+    public InstallSessionParams(int mode) {
+        this.mode = mode;
     }
 
     /** {@hide} */
@@ -72,34 +87,16 @@
         installFlags = source.readInt();
         installLocation = source.readInt();
         signatures = (Signature[]) source.readParcelableArray(null);
-        deltaSize = source.readLong();
-        progressMax = source.readInt();
-        packageName = source.readString();
-        icon = source.readParcelable(null);
-        title = source.readString();
+        sizeBytes = source.readLong();
+        appPackageName = source.readString();
+        appIcon = source.readParcelable(null);
+        appLabel = source.readString();
         originatingUri = source.readParcelable(null);
         referrerUri = source.readParcelable(null);
         abiOverride = source.readString();
     }
 
     /**
-     * Set session mode indicating that it should fully replace any existing
-     * APKs for this application.
-     */
-    public void setModeFullInstall() {
-        this.mode = MODE_FULL_INSTALL;
-    }
-
-    /**
-     * Set session mode indicating that it should inherit any existing APKs for
-     * this application, unless they are explicitly overridden (by split name)
-     * in the session.
-     */
-    public void setModeInheritExisting() {
-        this.mode = MODE_INHERIT_EXISTING;
-    }
-
-    /**
      * Provide value of {@link PackageInfo#installLocation}, which may be used
      * to determine where the app will be staged. Defaults to
      * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
@@ -109,56 +106,57 @@
     }
 
     /**
-     * Optionally provide the required value of {@link PackageInfo#signatures}.
-     * This can be used to assert that all staged APKs have been signed with
-     * this set of specific certificates. Regardless of this value, all APKs in
-     * the application must have the same signing certificates.
+     * Optionally provide a set of certificates for the app being installed.
+     * <p>
+     * If the APKs staged in the session aren't consistent with these
+     * signatures, the install will fail. Regardless of this value, all APKs in
+     * the app must have the same signing certificates.
+     *
+     * @see PackageInfo#signatures
      */
-    public void setSignatures(Signature[] signatures) {
+    public void setSignatures(@Nullable Signature[] signatures) {
         this.signatures = signatures;
     }
 
     /**
-     * Indicate the expected growth in disk usage resulting from this session.
-     * This may be used to ensure enough disk space exists before proceeding, or
-     * to estimate container size for installations living on external storage.
-     * <p>
-     * This value should only reflect APK sizes.
-     */
-    public void setDeltaSize(long deltaSize) {
-        this.deltaSize = deltaSize;
-    }
-
-    /**
-     * Set the maximum progress for this session, used for normalization
-     * purposes.
+     * Optionally indicate the total size (in bytes) of all APKs that will be
+     * delivered in this session. The system may use this to ensure enough disk
+     * space exists before proceeding, or to estimate container size for
+     * installations living on external storage.
      *
-     * @see PackageInstaller.Session#setProgress(int)
+     * @see PackageInfo#INSTALL_LOCATION_AUTO
+     * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
      */
-    public void setProgressMax(int progressMax) {
-        this.progressMax = progressMax;
+    public void setSize(long sizeBytes) {
+        this.sizeBytes = sizeBytes;
     }
 
     /**
-     * Optionally set the package name this session will be working with. It's
-     * strongly recommended that you provide this value when known.
+     * Optionally set the package name of the app being installed. It's strongly
+     * recommended that you provide this value when known, so that observers can
+     * communicate installing apps to users.
+     * <p>
+     * If the APKs staged in the session aren't consistent with this package
+     * name, the install will fail. Regardless of this value, all APKs in the
+     * app must have the same package name.
      */
-    public void setPackageName(String packageName) {
-        this.packageName = packageName;
+    public void setAppPackageName(@Nullable String appPackageName) {
+        this.appPackageName = appPackageName;
     }
 
     /**
-     * Optionally set an icon representing the app being installed.
+     * Optionally set an icon representing the app being installed. This should
+     * be at least {@link android.R.dimen#app_icon_size} in both dimensions.
      */
-    public void setIcon(Bitmap icon) {
-        this.icon = icon;
+    public void setAppIcon(@Nullable Bitmap appIcon) {
+        this.appIcon = appIcon;
     }
 
     /**
-     * Optionally set a title representing the app being installed.
+     * Optionally set a label representing the app being installed.
      */
-    public void setTitle(CharSequence title) {
-        this.title = title;
+    public void setAppLabel(@Nullable CharSequence appLabel) {
+        this.appLabel = appLabel;
     }
 
     /**
@@ -167,7 +165,7 @@
      *
      * @see Intent#EXTRA_ORIGINATING_URI
      */
-    public void setOriginatingUri(Uri originatingUri) {
+    public void setOriginatingUri(@Nullable Uri originatingUri) {
         this.originatingUri = originatingUri;
     }
 
@@ -177,7 +175,7 @@
      *
      * @see Intent#EXTRA_REFERRER
      */
-    public void setReferrerUri(Uri referrerUri) {
+    public void setReferrerUri(@Nullable Uri referrerUri) {
         this.referrerUri = referrerUri;
     }
 
@@ -187,11 +185,10 @@
         pw.printHexPair("installFlags", installFlags);
         pw.printPair("installLocation", installLocation);
         pw.printPair("signatures", (signatures != null));
-        pw.printPair("deltaSize", deltaSize);
-        pw.printPair("progressMax", progressMax);
-        pw.printPair("packageName", packageName);
-        pw.printPair("icon", (icon != null));
-        pw.printPair("title", title);
+        pw.printPair("sizeBytes", sizeBytes);
+        pw.printPair("appPackageName", appPackageName);
+        pw.printPair("appIcon", (appIcon != null));
+        pw.printPair("appLabel", appLabel);
         pw.printPair("originatingUri", originatingUri);
         pw.printPair("referrerUri", referrerUri);
         pw.printPair("abiOverride", abiOverride);
@@ -209,11 +206,10 @@
         dest.writeInt(installFlags);
         dest.writeInt(installLocation);
         dest.writeParcelableArray(signatures, flags);
-        dest.writeLong(deltaSize);
-        dest.writeInt(progressMax);
-        dest.writeString(packageName);
-        dest.writeParcelable(icon, flags);
-        dest.writeString(title != null ? title.toString() : null);
+        dest.writeLong(sizeBytes);
+        dest.writeString(appPackageName);
+        dest.writeParcelable(appIcon, flags);
+        dest.writeString(appLabel != null ? appLabel.toString() : null);
         dest.writeParcelable(originatingUri, flags);
         dest.writeParcelable(referrerUri, flags);
         dest.writeString(abiOverride);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 6e7a418..2d50b5a 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -230,6 +230,24 @@
     }
 
     /**
+     * Starts the settings activity to show the application details for a
+     * package in the specified profile.
+     *
+     * @param component The ComponentName of the package to launch settings for.
+     * @param user The UserHandle of the profile
+     * @param sourceBounds The Rect containing the source bounds of the clicked icon
+     * @param opts Options to pass to startActivity
+     */
+    public void showAppDetailsForProfile(ComponentName component, UserHandle user,
+            Rect sourceBounds, Bundle opts) {
+        try {
+            mService.showAppDetailsAsUser(component, sourceBounds, opts, user);
+        } catch (RemoteException re) {
+            // Oops!
+        }
+    }
+
+    /**
      * Checks if the package is installed and enabled for a profile.
      *
      * @param packageName The package to check.
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index df82d26..a114bb8 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -16,11 +16,16 @@
 
 package android.content.pm;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.PackageInstallObserver;
 import android.app.PackageUninstallObserver;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
 import android.os.FileBridge;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.ExceptionUtils;
@@ -28,6 +33,8 @@
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -61,6 +68,8 @@
     private final int mUserId;
     private final String mInstallerPackageName;
 
+    private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
+
     /** {@hide} */
     public PackageInstaller(PackageManager pm, IPackageInstaller installer,
             String installerPackageName, int userId) {
@@ -71,28 +80,6 @@
     }
 
     /**
-     * Quickly test if the given package is already available on the device.
-     * This is typically used in multi-user scenarios where another user on the
-     * device has already installed the package.
-     *
-     * @hide
-     */
-    public boolean isPackageAvailable(String packageName) {
-        return mPm.isPackageAvailable(packageName);
-    }
-
-    /** {@hide} */
-    public void installAvailablePackage(String packageName, PackageInstallObserver observer) {
-        int returnCode;
-        try {
-            returnCode = mPm.installExistingPackage(packageName);
-        } catch (NameNotFoundException e) {
-            returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
-        }
-        observer.packageInstalled(packageName, null, returnCode);
-    }
-
-    /**
      * Create a new session using the given parameters, returning a unique ID
      * that represents the session. Once created, the session can be opened
      * multiple times across multiple device boots.
@@ -104,9 +91,9 @@
      * @throws IOException if parameters were unsatisfiable, such as lack of
      *             disk space or unavailable media.
      */
-    public int createSession(InstallSessionParams params) throws IOException {
+    public int createSession(@NonNull InstallSessionParams params) throws IOException {
         try {
-            return mInstaller.createSession(mInstallerPackageName, params, mUserId);
+            return mInstaller.createSession(params, mInstallerPackageName, mUserId);
         } catch (RuntimeException e) {
             ExceptionUtils.maybeUnwrapIOException(e);
             throw e;
@@ -116,9 +103,10 @@
     }
 
     /**
-     * Open an existing session to actively perform work.
+     * Open an existing session to actively perform work. To succeed, the caller
+     * must be the owner of the install session.
      */
-    public Session openSession(int sessionId) {
+    public @NonNull Session openSession(int sessionId) {
         try {
             return new Session(mInstaller.openSession(sessionId));
         } catch (RemoteException e) {
@@ -127,13 +115,35 @@
     }
 
     /**
-     * Return list of all active install sessions on the device.
+     * Return details for a specific session. To succeed, the caller must either
+     * own this session, or be the current home app.
      */
-    public List<InstallSessionInfo> getActiveSessions() {
-        // TODO: filter based on caller
-        // TODO: let launcher app see all active sessions
+    public @Nullable InstallSessionInfo getSessionInfo(int sessionId) {
         try {
-            return mInstaller.getSessions(mUserId);
+            return mInstaller.getSessionInfo(sessionId);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Return list of all active install sessions, regardless of the installer.
+     * To succeed, the caller must be the current home app.
+     */
+    public @NonNull List<InstallSessionInfo> getAllSessions() {
+        try {
+            return mInstaller.getAllSessions(mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Return list of all install sessions owned by the calling app.
+     */
+    public @NonNull List<InstallSessionInfo> getMySessions() {
+        try {
+            return mInstaller.getMySessions(mInstallerPackageName, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -144,10 +154,10 @@
      * method is only available to the current "installer of record" for the
      * package.
      */
-    public void uninstall(String packageName, UninstallResultCallback callback) {
+    public void uninstall(@NonNull String packageName, @NonNull UninstallCallback callback) {
         try {
             mInstaller.uninstall(packageName, 0,
-                    new UninstallResultCallbackDelegate(callback).getBinder(), mUserId);
+                    new UninstallCallbackDelegate(callback).getBinder(), mUserId);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -158,10 +168,11 @@
      *
      * @hide
      */
-    public void uninstall(String packageName, String splitName, UninstallResultCallback callback) {
+    public void uninstall(@NonNull String packageName, @NonNull String splitName,
+            @NonNull UninstallCallback callback) {
         try {
             mInstaller.uninstallSplit(packageName, splitName, 0,
-                    new UninstallResultCallbackDelegate(callback).getBinder(), mUserId);
+                    new UninstallCallbackDelegate(callback).getBinder(), mUserId);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -170,69 +181,121 @@
     /**
      * Events for observing session lifecycle.
      */
-    public static abstract class SessionObserver {
-        private final IPackageInstallerObserver.Stub mBinder = new IPackageInstallerObserver.Stub() {
-            @Override
-            public void onSessionCreated(InstallSessionInfo info) {
-                SessionObserver.this.onCreated(info);
-            }
-
-            @Override
-            public void onSessionProgress(int sessionId, int progress) {
-                SessionObserver.this.onProgress(sessionId, progress);
-            }
-
-            @Override
-            public void onSessionFinished(int sessionId, boolean success) {
-                SessionObserver.this.onFinalized(sessionId, success);
-            }
-        };
-
-        /** {@hide} */
-        public IPackageInstallerObserver getBinder() {
-            return mBinder;
-        }
-
+    public static abstract class SessionCallback {
         /**
          * New session has been created.
          */
-        public abstract void onCreated(InstallSessionInfo info);
+        public abstract void onCreated(int sessionId);
 
         /**
          * Progress for given session has been updated.
          * <p>
          * Note that this progress may not directly correspond to the value
-         * reported by {@link PackageInstaller.Session#setProgress(int)}, as the
-         * system may carve out a portion of the overall progress to represent
-         * its own internal installation work.
+         * reported by {@link PackageInstaller.Session#setProgress(float)}, as
+         * the system may carve out a portion of the overall progress to
+         * represent its own internal installation work.
          */
-        public abstract void onProgress(int sessionId, int progress);
+        public abstract void onProgressChanged(int sessionId, float progress);
 
         /**
-         * Session has been finalized, either with success or failure.
+         * Session has completely finished, either with success or failure.
          */
-        public abstract void onFinalized(int sessionId, boolean success);
+        public abstract void onFinished(int sessionId, boolean success);
     }
 
-    /**
-     * Register to watch for session lifecycle events.
-     */
-    public void registerSessionObserver(SessionObserver observer) {
-        try {
-            mInstaller.registerObserver(observer.getBinder(), mUserId);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+    /** {@hide} */
+    private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
+            Handler.Callback {
+        private static final int MSG_SESSION_CREATED = 1;
+        private static final int MSG_SESSION_PROGRESS_CHANGED = 2;
+        private static final int MSG_SESSION_FINISHED = 3;
+
+        final SessionCallback mCallback;
+        final Handler mHandler;
+
+        public SessionCallbackDelegate(SessionCallback callback, Looper looper) {
+            mCallback = callback;
+            mHandler = new Handler(looper, this);
+        }
+
+        @Override
+        public boolean handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SESSION_CREATED:
+                    mCallback.onCreated(msg.arg1);
+                    return true;
+                case MSG_SESSION_PROGRESS_CHANGED:
+                    mCallback.onProgressChanged(msg.arg1, (float) msg.obj);
+                    return true;
+                case MSG_SESSION_FINISHED:
+                    mCallback.onFinished(msg.arg1, msg.arg2 != 0);
+                    return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void onSessionCreated(int sessionId) {
+            mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget();
+        }
+
+        @Override
+        public void onSessionProgressChanged(int sessionId, float progress) {
+            mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void onSessionFinished(int sessionId, boolean success) {
+            mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
+                    .sendToTarget();
         }
     }
 
     /**
-     * Unregister an existing observer.
+     * Register to watch for session lifecycle events. To succeed, the caller
+     * must be the current home app.
      */
-    public void unregisterSessionObserver(SessionObserver observer) {
-        try {
-            mInstaller.unregisterObserver(observer.getBinder(), mUserId);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+    public void addSessionCallback(@NonNull SessionCallback callback) {
+        addSessionCallback(callback, new Handler());
+    }
+
+    /**
+     * Register to watch for session lifecycle events. To succeed, the caller
+     * must be the current home app.
+     *
+     * @param handler to dispatch callback events through, otherwise uses
+     *            calling thread.
+     */
+    public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
+        synchronized (mDelegates) {
+            final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
+                    handler.getLooper());
+            try {
+                mInstaller.registerCallback(delegate, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+            mDelegates.add(delegate);
+        }
+    }
+
+    /**
+     * Unregister an existing callback.
+     */
+    public void removeSessionCallback(@NonNull SessionCallback callback) {
+        synchronized (mDelegates) {
+            for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
+                final SessionCallbackDelegate delegate = i.next();
+                if (delegate.mCallback == callback) {
+                    try {
+                        mInstaller.unregisterCallback(delegate);
+                    } catch (RemoteException e) {
+                        throw e.rethrowAsRuntimeException();
+                    }
+                    i.remove();
+                }
+            }
         }
     }
 
@@ -244,9 +307,9 @@
      * A session may contain any number of split packages. If the application
      * does not yet exist, this session must include a base package.
      * <p>
-     * If a package included in this session is already defined by the existing
-     * installation (for example, the same split name), the package in this
-     * session will replace the existing package.
+     * If an APK included in this session is already defined by the existing
+     * installation (for example, the same split name), the APK in this session
+     * will replace the existing APK.
      */
     public static class Session implements Closeable {
         private IPackageInstallerSession mSession;
@@ -257,10 +320,9 @@
         }
 
         /**
-         * Set current progress. Valid values are anywhere between 0 and
-         * {@link InstallSessionParams#setProgressMax(int)}.
+         * Set current progress. Valid values are anywhere between 0 and 1.
          */
-        public void setProgress(int progress) {
+        public void setProgress(float progress) {
             try {
                 mSession.setClientProgress(progress);
             } catch (RemoteException e) {
@@ -269,7 +331,7 @@
         }
 
         /** {@hide} */
-        public void addProgress(int progress) {
+        public void addProgress(float progress) {
             try {
                 mSession.addClientProgress(progress);
             } catch (RemoteException e) {
@@ -278,15 +340,33 @@
         }
 
         /**
-         * Open an APK file for writing, starting at the given offset. You can
-         * then stream data into the file, periodically calling
-         * {@link #fsync(OutputStream)} to ensure bytes have been written to
-         * disk.
+         * Open a stream to write an APK file into the session.
+         * <p>
+         * The returned stream will start writing data at the requested offset
+         * in the underlying file, which can be used to resume a partially
+         * written file. If a valid file length is specified, the system will
+         * preallocate the underlying disk space to optimize placement on disk.
+         * It's strongly recommended to provide a valid file length when known.
+         * <p>
+         * You can write data into the returned stream, optionally call
+         * {@link #fsync(OutputStream)} as needed to ensure bytes have been
+         * persisted to disk, and then close when finished. All streams must be
+         * closed before calling {@link #commit(CommitCallback)}.
+         *
+         * @param name arbitrary, unique name of your choosing to identify the
+         *            APK being written. You can open a file again for
+         *            additional writes (such as after a reboot) by using the
+         *            same name. This name is only meaningful within the context
+         *            of a single install session.
+         * @param offsetBytes offset into the file to begin writing at, or 0 to
+         *            start at the beginning of the file.
+         * @param lengthBytes total size of the file being written, used to
+         *            preallocate the underlying disk space, or -1 if unknown.
          */
-        public OutputStream openWrite(String splitName, long offsetBytes, long lengthBytes)
-                throws IOException {
+        public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
+                long lengthBytes) throws IOException {
             try {
-                final ParcelFileDescriptor clientSocket = mSession.openWrite(splitName,
+                final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
                         offsetBytes, lengthBytes);
                 return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor());
             } catch (RuntimeException e) {
@@ -302,7 +382,7 @@
          * to disk. This is only valid for streams returned from
          * {@link #openWrite(String, long, long)}.
          */
-        public void fsync(OutputStream out) throws IOException {
+        public void fsync(@NonNull OutputStream out) throws IOException {
             if (out instanceof FileBridge.FileBridgeOutputStream) {
                 ((FileBridge.FileBridgeOutputStream) out).fsync();
             } else {
@@ -319,9 +399,9 @@
          * on the session. If the device reboots before the session has been
          * finalized, you may commit the session again.
          */
-        public void commit(CommitResultCallback callback) {
+        public void commit(@NonNull CommitCallback callback) {
             try {
-                mSession.install(new CommitResultCallbackDelegate(callback).getBinder());
+                mSession.commit(new CommitCallbackDelegate(callback).getBinder());
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
             }
@@ -333,15 +413,20 @@
          */
         @Override
         public void close() {
-            // No resources to release at the moment
+            try {
+                mSession.close();
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
         }
 
         /**
-         * Completely destroy this session, rendering it invalid.
+         * Completely abandon this session, destroying all staged data and
+         * rendering it invalid.
          */
-        public void destroy() {
+        public void abandon() {
             try {
-                mSession.destroy();
+                mSession.abandon();
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
             }
@@ -351,30 +436,26 @@
     /**
      * Final result of an uninstall request.
      */
-    public static abstract class UninstallResultCallback {
+    public static abstract class UninstallCallback {
         public abstract void onSuccess();
         public abstract void onFailure(String msg);
     }
 
     /** {@hide} */
-    private static class UninstallResultCallbackDelegate extends PackageUninstallObserver {
-        private final UninstallResultCallback target;
+    private static class UninstallCallbackDelegate extends PackageUninstallObserver {
+        private final UninstallCallback target;
 
-        public UninstallResultCallbackDelegate(UninstallResultCallback target) {
+        public UninstallCallbackDelegate(UninstallCallback target) {
             this.target = target;
         }
 
         @Override
         public void onUninstallFinished(String basePackageName, int returnCode) {
-            final String msg = null;
-
-            switch (returnCode) {
-                case PackageManager.DELETE_SUCCEEDED: target.onSuccess(); break;
-                case PackageManager.DELETE_FAILED_INTERNAL_ERROR: target.onFailure("DELETE_FAILED_INTERNAL_ERROR: " + msg); break;
-                case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER: target.onFailure("DELETE_FAILED_DEVICE_POLICY_MANAGER: " + msg); break;
-                case PackageManager.DELETE_FAILED_USER_RESTRICTED: target.onFailure("DELETE_FAILED_USER_RESTRICTED: " + msg); break;
-                case PackageManager.DELETE_FAILED_OWNER_BLOCKED: target.onFailure("DELETE_FAILED_OWNER_BLOCKED: " + msg); break;
-                default: target.onFailure(msg); break;
+            if (returnCode == PackageManager.DELETE_SUCCEEDED) {
+                target.onSuccess();
+            } else {
+                final String msg = PackageManager.deleteStatusToString(returnCode);
+                target.onFailure(msg);
             }
         }
     }
@@ -382,16 +463,13 @@
     /**
      * Final result of a session commit request.
      */
-    public static abstract class CommitResultCallback {
-        public abstract void onSuccess();
-
+    public static abstract class CommitCallback {
         /**
-         * Generic failure occurred. You can override methods (such as
-         * {@link #onFailureInvalid(String)}) to handle more specific categories
-         * of failure. By default, those specific categories all flow into this
-         * generic failure.
+         * Generic unknown failure. The system will always try to provide a more
+         * specific failure reason, but in some rare cases this may be
+         * delivered.
          */
-        public abstract void onFailure(String msg);
+        public static final int FAILURE_UNKNOWN = 0;
 
         /**
          * One or more of the APKs included in the session was invalid. For
@@ -399,23 +477,19 @@
          * mismatched, etc. The installer may want to try downloading and
          * installing again.
          */
-        public void onFailureInvalid(String msg) {
-            onFailure(msg);
-        }
+        public static final int FAILURE_INVALID = 1;
 
         /**
          * This install session conflicts (or is inconsistent with) with another
          * package already installed on the device. For example, an existing
          * permission, incompatible certificates, etc. The user may be able to
          * uninstall another app to fix the issue.
-         *
-         * @param otherPackageName if one specific package was identified as the
-         *            cause of the conflict, it's named here. If unknown, or
-         *            multiple packages, this may be {@code null}.
+         * <p>
+         * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} if one
+         * specific package was identified as the cause of the conflict. If
+         * unknown, or multiple packages, the extra may be {@code null}.
          */
-        public void onFailureConflict(String msg, String otherPackageName) {
-            onFailure(msg);
-        }
+        public static final int FAILURE_CONFLICT = 2;
 
         /**
          * This install session failed due to storage issues. For example,
@@ -423,9 +497,7 @@
          * media may be unavailable. The user may be able to help free space
          * or insert the correct media.
          */
-        public void onFailureStorage(String msg) {
-            onFailure(msg);
-        }
+        public static final int FAILURE_STORAGE = 3;
 
         /**
          * This install session is fundamentally incompatible with this
@@ -434,66 +506,37 @@
          * ABI, or it requires a newer SDK version, etc. This install would
          * never succeed.
          */
-        public void onFailureIncompatible(String msg) {
-            onFailure(msg);
-        }
+        public static final int FAILURE_INCOMPATIBLE = 4;
+
+        public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+
+        public abstract void onSuccess();
+        public abstract void onFailure(int failureReason, String msg, Bundle extras);
     }
 
     /** {@hide} */
-    private static class CommitResultCallbackDelegate extends PackageInstallObserver {
-        private final CommitResultCallback target;
+    private static class CommitCallbackDelegate extends PackageInstallObserver {
+        private final CommitCallback target;
 
-        public CommitResultCallbackDelegate(CommitResultCallback target) {
+        public CommitCallbackDelegate(CommitCallback target) {
             this.target = target;
         }
 
         @Override
         public void packageInstalled(String basePackageName, Bundle extras, int returnCode,
                 String msg) {
-            final String otherPackage = null;
+            if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                target.onSuccess();
+            } else {
+                final int failureReason = PackageManager.installStatusToFailureReason(returnCode);
+                msg = PackageManager.installStatusToString(returnCode) + ": " + msg;
 
-            switch (returnCode) {
-                case PackageManager.INSTALL_SUCCEEDED: target.onSuccess(); break;
-                case PackageManager.INSTALL_FAILED_ALREADY_EXISTS: target.onFailureConflict("INSTALL_FAILED_ALREADY_EXISTS: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_INVALID_APK: target.onFailureInvalid("INSTALL_FAILED_INVALID_APK: " + msg); break;
-                case PackageManager.INSTALL_FAILED_INVALID_URI: target.onFailureInvalid("INSTALL_FAILED_INVALID_URI: " + msg); break;
-                case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE: target.onFailureStorage("INSTALL_FAILED_INSUFFICIENT_STORAGE: " + msg); break;
-                case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PACKAGE: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_NO_SHARED_USER: target.onFailureConflict("INSTALL_FAILED_NO_SHARED_USER: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_UPDATE_INCOMPATIBLE: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY: target.onFailureIncompatible("INSTALL_FAILED_MISSING_SHARED_LIBRARY: " + msg); break;
-                case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE: target.onFailureConflict("INSTALL_FAILED_REPLACE_COULDNT_DELETE: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_DEXOPT: target.onFailureInvalid("INSTALL_FAILED_DEXOPT: " + msg); break;
-                case PackageManager.INSTALL_FAILED_OLDER_SDK: target.onFailureIncompatible("INSTALL_FAILED_OLDER_SDK: " + msg); break;
-                case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER: target.onFailureConflict("INSTALL_FAILED_CONFLICTING_PROVIDER: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_NEWER_SDK: target.onFailureIncompatible("INSTALL_FAILED_NEWER_SDK: " + msg); break;
-                case PackageManager.INSTALL_FAILED_TEST_ONLY: target.onFailureInvalid("INSTALL_FAILED_TEST_ONLY: " + msg); break;
-                case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: target.onFailureIncompatible("INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: " + msg); break;
-                case PackageManager.INSTALL_FAILED_MISSING_FEATURE: target.onFailureIncompatible("INSTALL_FAILED_MISSING_FEATURE: " + msg); break;
-                case PackageManager.INSTALL_FAILED_CONTAINER_ERROR: target.onFailureStorage("INSTALL_FAILED_CONTAINER_ERROR: " + msg); break;
-                case PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION: target.onFailureStorage("INSTALL_FAILED_INVALID_INSTALL_LOCATION: " + msg); break;
-                case PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE: target.onFailureStorage("INSTALL_FAILED_MEDIA_UNAVAILABLE: " + msg); break;
-                case PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT: target.onFailure("INSTALL_FAILED_VERIFICATION_TIMEOUT: " + msg); break;
-                case PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE: target.onFailure("INSTALL_FAILED_VERIFICATION_FAILURE: " + msg); break;
-                case PackageManager.INSTALL_FAILED_PACKAGE_CHANGED: target.onFailureInvalid("INSTALL_FAILED_PACKAGE_CHANGED: " + msg); break;
-                case PackageManager.INSTALL_FAILED_UID_CHANGED: target.onFailureInvalid("INSTALL_FAILED_UID_CHANGED: " + msg); break;
-                case PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE: target.onFailureInvalid("INSTALL_FAILED_VERSION_DOWNGRADE: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: target.onFailureInvalid("INSTALL_PARSE_FAILED_NOT_APK: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_MANIFEST: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: target.onFailureInvalid("INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_NO_CERTIFICATES: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: target.onFailureInvalid("INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: " + msg); break;
-                case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_EMPTY: " + msg); break;
-                case PackageManager.INSTALL_FAILED_INTERNAL_ERROR: target.onFailure("INSTALL_FAILED_INTERNAL_ERROR: " + msg); break;
-                case PackageManager.INSTALL_FAILED_USER_RESTRICTED: target.onFailureIncompatible("INSTALL_FAILED_USER_RESTRICTED: " + msg); break;
-                case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PERMISSION: " + msg, otherPackage); break;
-                case PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS: target.onFailureInvalid("INSTALL_FAILED_NO_MATCHING_ABIS: " + msg); break;
-                default: target.onFailure(msg); break;
+                if (extras != null) {
+                    extras.putString(CommitCallback.EXTRA_PACKAGE_NAME,
+                            extras.getString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE));
+                }
+
+                target.onFailure(failureReason, msg, extras);
             }
         }
     }
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 9f79a89..4b5bdda 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -152,15 +152,9 @@
      * such as the default activity icon.
      */
     public Drawable loadIcon(PackageManager pm) {
-        if (icon != 0 || showUserIcon != UserHandle.USER_NULL) {
-            Drawable dr = pm.loadItemIcon(this, getApplicationInfo());
-            if (dr != null) {
-                return dr;
-            }
-        }
-        return loadDefaultIcon(pm);
+        return pm.loadItemIcon(this, getApplicationInfo());
     }
-    
+
     /**
      * Retrieve the current graphical banner associated with this item.  This
      * will call back on the given PackageManager to load the banner from
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8b6ae41..c5dcd8e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -26,6 +27,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.PackageInstaller.CommitCallback;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -203,13 +205,6 @@
     public static final int NO_CROSS_PROFILE = 0x00020000;
 
     /**
-     * Flag for {@link addCrossProfileIntentFilter}: if the cross-profile intent has been set by the
-     * profile owner.
-     * @hide
-     */
-    public static final int SET_BY_PROFILE_OWNER= 0x00000001;
-
-    /**
      * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
      * when resolving an intent that matches the {@link CrossProfileIntentFilter}, the current
      * profile will be skipped.
@@ -3723,7 +3718,7 @@
      * Return interface that offers the ability to install, upgrade, and remove
      * applications on the device.
      */
-    public abstract PackageInstaller getInstaller();
+    public abstract @NonNull PackageInstaller getPackageInstaller();
 
     /**
      * Returns the data directory for a particular user and package, given the uid of the package.
@@ -3742,9 +3737,10 @@
      * Adds a {@link CrossProfileIntentFilter}. After calling this method all intents sent from the
      * user with id sourceUserId can also be be resolved by activities in the user with id
      * targetUserId if they match the specified intent filter.
-     * @param filter the {@link IntentFilter} the intent has to match
-     * @param removable if set to false, {@link clearCrossProfileIntentFilters} will not remove this
-     * {@link CrossProfileIntentFilter}
+     * @param filter The {@link IntentFilter} the intent has to match
+     * @param sourceUserId The source user id.
+     * @param targetUserId The target user id.
+     * @param flags The only possible value is {@link SKIP_CURRENT_PROFILE}
      * @hide
      */
     public abstract void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId,
@@ -3752,8 +3748,8 @@
 
     /**
      * Clearing {@link CrossProfileIntentFilter}s which have the specified user as their
-     * source, and have been set by the profile owner
-     * @param sourceUserId
+     * source, and have been set by the app calling this method.
+     * @param sourceUserId The source user id.
      * @hide
      */
     public abstract void clearCrossProfileIntentFilters(int sourceUserId);
@@ -3772,4 +3768,109 @@
 
     /** {@hide} */
     public abstract boolean isPackageAvailable(String packageName);
+
+    /** {@hide} */
+    public static String installStatusToString(int status) {
+        switch (status) {
+            case INSTALL_SUCCEEDED: return "INSTALL_SUCCEEDED";
+            case INSTALL_FAILED_ALREADY_EXISTS: return "INSTALL_FAILED_ALREADY_EXISTS";
+            case INSTALL_FAILED_INVALID_APK: return "INSTALL_FAILED_INVALID_APK";
+            case INSTALL_FAILED_INVALID_URI: return "INSTALL_FAILED_INVALID_URI";
+            case INSTALL_FAILED_INSUFFICIENT_STORAGE: return "INSTALL_FAILED_INSUFFICIENT_STORAGE";
+            case INSTALL_FAILED_DUPLICATE_PACKAGE: return "INSTALL_FAILED_DUPLICATE_PACKAGE";
+            case INSTALL_FAILED_NO_SHARED_USER: return "INSTALL_FAILED_NO_SHARED_USER";
+            case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return "INSTALL_FAILED_UPDATE_INCOMPATIBLE";
+            case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return "INSTALL_FAILED_SHARED_USER_INCOMPATIBLE";
+            case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return "INSTALL_FAILED_MISSING_SHARED_LIBRARY";
+            case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return "INSTALL_FAILED_REPLACE_COULDNT_DELETE";
+            case INSTALL_FAILED_DEXOPT: return "INSTALL_FAILED_DEXOPT";
+            case INSTALL_FAILED_OLDER_SDK: return "INSTALL_FAILED_OLDER_SDK";
+            case INSTALL_FAILED_CONFLICTING_PROVIDER: return "INSTALL_FAILED_CONFLICTING_PROVIDER";
+            case INSTALL_FAILED_NEWER_SDK: return "INSTALL_FAILED_NEWER_SDK";
+            case INSTALL_FAILED_TEST_ONLY: return "INSTALL_FAILED_TEST_ONLY";
+            case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return "INSTALL_FAILED_CPU_ABI_INCOMPATIBLE";
+            case INSTALL_FAILED_MISSING_FEATURE: return "INSTALL_FAILED_MISSING_FEATURE";
+            case INSTALL_FAILED_CONTAINER_ERROR: return "INSTALL_FAILED_CONTAINER_ERROR";
+            case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return "INSTALL_FAILED_INVALID_INSTALL_LOCATION";
+            case INSTALL_FAILED_MEDIA_UNAVAILABLE: return "INSTALL_FAILED_MEDIA_UNAVAILABLE";
+            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return "INSTALL_FAILED_VERIFICATION_TIMEOUT";
+            case INSTALL_FAILED_VERIFICATION_FAILURE: return "INSTALL_FAILED_VERIFICATION_FAILURE";
+            case INSTALL_FAILED_PACKAGE_CHANGED: return "INSTALL_FAILED_PACKAGE_CHANGED";
+            case INSTALL_FAILED_UID_CHANGED: return "INSTALL_FAILED_UID_CHANGED";
+            case INSTALL_FAILED_VERSION_DOWNGRADE: return "INSTALL_FAILED_VERSION_DOWNGRADE";
+            case INSTALL_PARSE_FAILED_NOT_APK: return "INSTALL_PARSE_FAILED_NOT_APK";
+            case INSTALL_PARSE_FAILED_BAD_MANIFEST: return "INSTALL_PARSE_FAILED_BAD_MANIFEST";
+            case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return "INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION";
+            case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return "INSTALL_PARSE_FAILED_NO_CERTIFICATES";
+            case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return "INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES";
+            case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return "INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING";
+            case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME";
+            case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return "INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID";
+            case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return "INSTALL_PARSE_FAILED_MANIFEST_MALFORMED";
+            case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return "INSTALL_PARSE_FAILED_MANIFEST_EMPTY";
+            case INSTALL_FAILED_INTERNAL_ERROR: return "INSTALL_FAILED_INTERNAL_ERROR";
+            case INSTALL_FAILED_USER_RESTRICTED: return "INSTALL_FAILED_USER_RESTRICTED";
+            case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION";
+            case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS";
+            default: return Integer.toString(status);
+        }
+    }
+
+    /** {@hide} */
+    public static int installStatusToFailureReason(int status) {
+        switch (status) {
+            case INSTALL_FAILED_ALREADY_EXISTS: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_INVALID_APK: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_FAILED_INVALID_URI: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_FAILED_INSUFFICIENT_STORAGE: return CommitCallback.FAILURE_STORAGE;
+            case INSTALL_FAILED_DUPLICATE_PACKAGE: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_NO_SHARED_USER: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return CommitCallback.FAILURE_INCOMPATIBLE;
+            case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_DEXOPT: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_FAILED_OLDER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE;
+            case INSTALL_FAILED_CONFLICTING_PROVIDER: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_NEWER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE;
+            case INSTALL_FAILED_TEST_ONLY: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return CommitCallback.FAILURE_INCOMPATIBLE;
+            case INSTALL_FAILED_MISSING_FEATURE: return CommitCallback.FAILURE_INCOMPATIBLE;
+            case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE;
+            case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE;
+            case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE;
+            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_UNKNOWN;
+            case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_UNKNOWN;
+            case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_NOT_APK: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_BAD_MANIFEST: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return CommitCallback.FAILURE_INVALID;
+            case INSTALL_FAILED_INTERNAL_ERROR: return CommitCallback.FAILURE_UNKNOWN;
+            case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE;
+            case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT;
+            case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE;
+            default: return CommitCallback.FAILURE_UNKNOWN;
+        }
+    }
+
+    /** {@hide} */
+    public static String deleteStatusToString(int status) {
+        switch (status) {
+            case DELETE_SUCCEEDED: return "DELETE_SUCCEEDED";
+            case DELETE_FAILED_INTERNAL_ERROR: return "DELETE_FAILED_INTERNAL_ERROR";
+            case DELETE_FAILED_DEVICE_POLICY_MANAGER: return "DELETE_FAILED_DEVICE_POLICY_MANAGER";
+            case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED";
+            case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED";
+            default: return Integer.toString(status);
+        }
+    }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9866200..db87cf7 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1530,6 +1530,11 @@
 
                 XmlUtils.skipCurrentTag(parser);
 
+            } else if (tagName.equals("feature-group")) {
+                // Skip this for now until we know what to do with it.
+
+                XmlUtils.skipCurrentTag(parser);
+
             } else if (tagName.equals("uses-sdk")) {
                 if (SDK_VERSION > 0) {
                     sa = res.obtainAttributes(attrs,
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index a5c2f63..b6d2a13 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -781,6 +781,25 @@
      */
     public static final String STRING_TYPE_GLANCE_GESTURE = "android.sensor.glance_gesture";
 
+     /**
+     * A constant describing a pick up sensor.
+     *
+     * A sensor of this type triggers when the device is picked up regardless of wherever it was
+     * before (desk, pocket, bag). The only allowed return value is 1.0. This sensor deactivates
+     * itself immediately after it triggers.
+     *
+     * @hide Expected to be used internally for always on display.
+     */
+    public static final int TYPE_PICK_UP_GESTURE = 44;
+
+    /**
+     * A constant string describing a pick up sensor.
+     *
+     * @hide This sensor is expected to be used internally for always on display.
+     * @see #TYPE_PICK_UP_GESTURE
+     */
+    public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
+
     /**
      * A constant describing all sensor types.
      */
@@ -880,6 +899,7 @@
             1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
             1, // SENSOR_TYPE_WAKE_GESTURE
             1, // SENSOR_TYPE_GLANCE_GESTURE
+            1, // SENSOR_TYPE_PICK_UP_GESTURE
     };
 
     /**
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index f18cb7d..6cb6a24 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1810,33 +1810,6 @@
             new Key<Integer>("android.sensor.orientation", int.class);
 
     /**
-     * <p>Noise model coefficients for each CFA mosaic channel.</p>
-     * <p>This tag contains two noise model coefficients for each CFA channel
-     * corresponding to the sensor amplification (S) and sensor readout
-     * noise (O).  These are given as pairs of coefficients for each channel
-     * in the same order as channels listed for the CFA layout tag
-     * (see {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}).  This is
-     * represented as an array of Pair&lt;Double, Double&gt;, where
-     * the first member of the Pair at index n is the S coefficient and the
-     * second member is the O coefficient for the nth color channel in the CFA.</p>
-     * <p>These coefficients are used in a two parameter noise model to describe
-     * the amount of noise present in the image for each CFA channel.  The
-     * noise model used here is:</p>
-     * <p>N(x) = sqrt(Sx + O)</p>
-     * <p>Where x represents the recorded signal of a CFA channel normalized to
-     * the range [0, 1], and S and O are the noise model coeffiecients for
-     * that channel.</p>
-     * <p>A more detailed description of the noise model can be found in the
-     * Adobe DNG specification for the NoiseProfile tag.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     *
-     * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
-     */
-    @PublicKey
-    public static final Key<android.util.Pair<Double,Double>[]> SENSOR_NOISE_PROFILE =
-            new Key<android.util.Pair<Double,Double>[]>("android.sensor.noiseProfile", new TypeReference<android.util.Pair<Double,Double>[]>() {{ }});
-
-    /**
      * <p>Lists the supported sensor test pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
      * <p>Optional. Defaults to [OFF].</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 9a3d806..a4a1559 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -23,7 +23,7 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.legacy.CameraDeviceUserShim;
 import android.hardware.camera2.legacy.LegacyMetadataMapper;
-import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.camera2.utils.CameraServiceBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.hardware.camera2.utils.BinderHolder;
 import android.os.IBinder;
@@ -52,6 +52,7 @@
 public final class CameraManager {
 
     private static final String TAG = "CameraManager";
+    private final boolean DEBUG;
 
     /**
      * This should match the ICameraService definition
@@ -63,7 +64,9 @@
     private static final int API_VERSION_1 = 1;
     private static final int API_VERSION_2 = 2;
 
-    private final ICameraService mCameraService;
+    // Access only through getCameraServiceLocked to deal with binder death
+    private ICameraService mCameraService;
+
     private ArrayList<String> mDeviceIdList;
 
     private final ArrayMap<AvailabilityListener, Handler> mListenerMap =
@@ -72,35 +75,17 @@
     private final Context mContext;
     private final Object mLock = new Object();
 
+    private final CameraServiceListener mServiceListener = new CameraServiceListener();
+
     /**
      * @hide
      */
     public CameraManager(Context context) {
-        mContext = context;
+        DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+        synchronized(mLock) {
+            mContext = context;
 
-        IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
-        ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
-
-        /**
-         * Wrap the camera service in a decorator which automatically translates return codes
-         * into exceptions, and RemoteExceptions into other exceptions.
-         */
-        mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw);
-
-        try {
-            CameraBinderDecorator.throwOnError(
-                    CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
-        } catch (CameraRuntimeException e) {
-            handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
-        }
-
-        try {
-            mCameraService.addListener(new CameraServiceListener());
-        } catch(CameraRuntimeException e) {
-            throw new IllegalStateException("Failed to register a camera service listener",
-                    e.asChecked());
-        } catch (RemoteException e) {
-            // impossible
+            connectCameraServiceLocked();
         }
     }
 
@@ -116,13 +101,9 @@
      */
     public String[] getCameraIdList() throws CameraAccessException {
         synchronized (mLock) {
-            try {
-                return getOrCreateDeviceIdListLocked().toArray(new String[0]);
-            } catch(CameraAccessException e) {
-                // this should almost never happen, except if mediaserver crashes
-                throw new IllegalStateException(
-                        "Failed to query camera service for device ID list", e);
-            }
+            // ID list creation handles various known failures in device enumeration, so only
+            // exceptions it'll throw are unexpected, and should be propagated upward.
+            return getOrCreateDeviceIdListLocked().toArray(new String[0]);
         }
     }
 
@@ -132,6 +113,9 @@
      * <p>Registering the same listener again will replace the handler with the
      * new one provided.</p>
      *
+     * <p>The first time a listener is registered, it is immediately called
+     * with the availability status of all currently known camera devices.</p>
+     *
      * @param listener The new listener to send camera availability notices to
      * @param handler The handler on which the listener should be invoked, or
      * {@code null} to use the current thread's {@link android.os.Looper looper}.
@@ -147,10 +131,11 @@
         }
 
         synchronized (mLock) {
-            mListenerMap.put(listener, handler);
-
-            // TODO: fire the current oldest known state when adding a new listener
-            //    (must be done while holding lock)
+            Handler oldHandler = mListenerMap.put(listener, handler);
+            // For new listeners, provide initial availability information
+            if (oldHandler == null) {
+                mServiceListener.updateListenerLocked(listener, handler);
+            }
         }
     }
 
@@ -176,64 +161,67 @@
      * @return The properties of the given camera
      *
      * @throws IllegalArgumentException if the cameraId does not match any
-     * currently connected camera device.
-     * @throws CameraAccessException if the camera is disabled by device policy.
+     *         known camera device.
+     * @throws CameraAccessException if the camera is disabled by device policy, or
+     *         the camera device has been disconnected.
      * @throws SecurityException if the application does not have permission to
-     * access the camera
+     *         access the camera
      *
      * @see #getCameraIdList
      * @see android.app.admin.DevicePolicyManager#setCameraDisabled
      */
     public CameraCharacteristics getCameraCharacteristics(String cameraId)
             throws CameraAccessException {
+        CameraCharacteristics characteristics = null;
 
         synchronized (mLock) {
             if (!getOrCreateDeviceIdListLocked().contains(cameraId)) {
                 throw new IllegalArgumentException(String.format("Camera id %s does not match any" +
                         " currently connected camera device", cameraId));
             }
-        }
 
-        int id = Integer.valueOf(cameraId);
+            int id = Integer.valueOf(cameraId);
 
-        /*
-         * Get the camera characteristics from the camera service directly if it supports it,
-         * otherwise get them from the legacy shim instead.
-         */
+            /*
+             * Get the camera characteristics from the camera service directly if it supports it,
+             * otherwise get them from the legacy shim instead.
+             */
 
-        if (!supportsCamera2Api(cameraId)) {
-            // Legacy backwards compatibility path; build static info from the camera parameters
-            String[] outParameters = new String[1];
+            ICameraService cameraService = getCameraServiceLocked();
+            if (cameraService == null) {
+                throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                        "Camera service is currently unavailable");
+            }
             try {
-                mCameraService.getLegacyParameters(id, /*out*/outParameters);
-                String parameters = outParameters[0];
+                if (!supportsCamera2ApiLocked(cameraId)) {
+                    // Legacy backwards compatibility path; build static info from the camera
+                    // parameters
+                    String[] outParameters = new String[1];
 
-                CameraInfo info = new CameraInfo();
-                mCameraService.getCameraInfo(id, /*out*/info);
+                    cameraService.getLegacyParameters(id, /*out*/outParameters);
+                    String parameters = outParameters[0];
 
-                return LegacyMetadataMapper.createCharacteristics(parameters, info);
-            } catch (RemoteException e) {
-                // Impossible
-                return null;
+                    CameraInfo info = new CameraInfo();
+                    cameraService.getCameraInfo(id, /*out*/info);
+
+                    characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
+                } else {
+                    // Normal path: Get the camera characteristics directly from the camera service
+                    CameraMetadataNative info = new CameraMetadataNative();
+
+                    cameraService.getCameraCharacteristics(id, info);
+
+                    characteristics = new CameraCharacteristics(info);
+                }
             } catch (CameraRuntimeException e) {
                 throw e.asChecked();
+            } catch (RemoteException e) {
+                // Camera service died - act as if the camera was disconnected
+                throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                        "Camera service is currently unavailable", e);
             }
-
-        } else {
-            // Normal path: Get the camera characteristics directly from the camera service
-            CameraMetadataNative info = new CameraMetadataNative();
-
-            try {
-                mCameraService.getCameraCharacteristics(id, info);
-            } catch(CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch(RemoteException e) {
-                // impossible
-                return null;
-            }
-
-            return new CameraCharacteristics(info);
         }
+        return characteristics;
     }
 
     /**
@@ -278,10 +266,16 @@
                 ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
                 int id = Integer.parseInt(cameraId);
                 try {
-                    if (supportsCamera2Api(cameraId)) {
+                    if (supportsCamera2ApiLocked(cameraId)) {
                         // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
-                        mCameraService.connectDevice(callbacks, id, mContext.getPackageName(),
-                                USE_CALLING_UID, holder);
+                        ICameraService cameraService = getCameraServiceLocked();
+                        if (cameraService == null) {
+                            throw new CameraRuntimeException(
+                                CameraAccessException.CAMERA_DISCONNECTED,
+                                "Camera service is currently unavailable");
+                        }
+                        cameraService.connectDevice(callbacks, id,
+                                mContext.getPackageName(), USE_CALLING_UID, holder);
                         cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
                     } else {
                         // Use legacy camera implementation for HAL1 devices
@@ -304,12 +298,19 @@
                         if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
                                 e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) {
                             // Per API docs, these failures call onError and throw
-                            throw e;
+                            throw e.asChecked();
                         }
                     } else {
                         // Unexpected failure - rethrow
                         throw e;
                     }
+                } catch (RemoteException e) {
+                    // Camera service died - act as if it's a CAMERA_DISCONNECTED case
+                    CameraRuntimeException ce = new CameraRuntimeException(
+                        CameraAccessException.CAMERA_DISCONNECTED,
+                        "Camera service is currently unavailable", e);
+                    deviceImpl.setRemoteFailure(ce);
+                    throw ce.asChecked();
                 }
 
                 // TODO: factor out listener to be non-nested, then move setter to constructor
@@ -324,8 +325,6 @@
                     + cameraId);
         } catch (CameraRuntimeException e) {
             throw e.asChecked();
-        } catch (RemoteException e) {
-            // impossible
         }
         return device;
     }
@@ -444,27 +443,38 @@
         }
     }
 
+    /**
+     * Return or create the list of currently connected camera devices.
+     *
+     * <p>In case of errors connecting to the camera service, will return an empty list.</p>
+     */
     private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
         if (mDeviceIdList == null) {
             int numCameras = 0;
+            ICameraService cameraService = getCameraServiceLocked();
+            ArrayList<String> deviceIdList = new ArrayList<>();
+
+            // If no camera service, then no devices
+            if (cameraService == null) {
+                return deviceIdList;
+            }
 
             try {
-                numCameras = mCameraService.getNumberOfCameras();
+                numCameras = cameraService.getNumberOfCameras();
             } catch(CameraRuntimeException e) {
                 throw e.asChecked();
             } catch (RemoteException e) {
-                // impossible
-                return null;
+                // camera service just died - if no camera service, then no devices
+                return deviceIdList;
             }
 
-            mDeviceIdList = new ArrayList<String>();
             CameraMetadataNative info = new CameraMetadataNative();
             for (int i = 0; i < numCameras; ++i) {
                 // Non-removable cameras use integers starting at 0 for their
                 // identifiers
                 boolean isDeviceSupported = false;
                 try {
-                    mCameraService.getCameraCharacteristics(i, info);
+                    cameraService.getCameraCharacteristics(i, info);
                     if (!info.isEmpty()) {
                         isDeviceSupported = true;
                     } else {
@@ -474,16 +484,26 @@
                     // Got a BAD_VALUE from service, meaning that this
                     // device is not supported.
                 } catch(CameraRuntimeException e) {
-                    throw e.asChecked();
+                    // DISCONNECTED means that the HAL reported an low-level error getting the
+                    // device info; skip listing the device.  Other errors,
+                    // propagate exception onward
+                    if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
+                        throw e.asChecked();
+                    }
                 } catch(RemoteException e) {
-                    // impossible
+                    // Camera service died - no devices to list
+                    deviceIdList.clear();
+                    return deviceIdList;
                 }
 
                 if (isDeviceSupported) {
-                    mDeviceIdList.add(String.valueOf(i));
+                    deviceIdList.add(String.valueOf(i));
+                } else {
+                    Log.w(TAG, "Error querying camera device " + i + " for listing.");
                 }
-            }
 
+            }
+            mDeviceIdList = deviceIdList;
         }
         return mDeviceIdList;
     }
@@ -506,8 +526,8 @@
      * @param cameraId a non-{@code null} camera identifier
      * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise.
      */
-    private boolean supportsCamera2Api(String cameraId) {
-        return supportsCameraApi(cameraId, API_VERSION_2);
+    private boolean supportsCamera2ApiLocked(String cameraId) {
+        return supportsCameraApiLocked(cameraId, API_VERSION_2);
     }
 
     /**
@@ -517,33 +537,125 @@
      * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2}
      * @return {@code true} if connecting will work for that device version.
      */
-    private boolean supportsCameraApi(String cameraId, int apiVersion) {
+    private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
         int id = Integer.parseInt(cameraId);
 
         /*
          * Possible return values:
-         * - NO_ERROR => Camera2 API is supported
-         * - CAMERA_DEPRECATED_HAL => Camera2 API is *not* supported (thrown as an exception)
+         * - NO_ERROR => CameraX API is supported
+         * - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception)
+         * - Remote exception => If the camera service died
          *
          * Anything else is an unexpected error we don't want to recover from.
          */
-
         try {
-            int res = mCameraService.supportsCameraApi(id, apiVersion);
+            ICameraService cameraService = getCameraServiceLocked();
+            // If no camera service, no support
+            if (cameraService == null) return false;
 
-            if (res != CameraBinderDecorator.NO_ERROR) {
+            int res = cameraService.supportsCameraApi(id, apiVersion);
+
+            if (res != CameraServiceBinderDecorator.NO_ERROR) {
                 throw new AssertionError("Unexpected value " + res);
             }
-
             return true;
         } catch (CameraRuntimeException e) {
-            if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
-                return false;
-            } else {
+            if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) {
                 throw e;
             }
+            // API level is not supported
         } catch (RemoteException e) {
-            throw new AssertionError("Camera service unreachable", e);
+            // Camera service is now down, no support for any API level
+        }
+        return false;
+    }
+
+    /**
+     * Connect to the camera service if it's available, and set up listeners.
+     *
+     * <p>Sets mCameraService to a valid pointer or null if the connection does not succeed.</p>
+     */
+    private void connectCameraServiceLocked() {
+        mCameraService = null;
+        IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
+        if (cameraServiceBinder == null) {
+            // Camera service is now down, leave mCameraService as null
+            return;
+        }
+        try {
+            cameraServiceBinder.linkToDeath(new CameraServiceDeathListener(), /*flags*/ 0);
+        } catch (RemoteException e) {
+            // Camera service is now down, leave mCameraService as null
+            return;
+        }
+
+        ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
+
+        /**
+         * Wrap the camera service in a decorator which automatically translates return codes
+         * into exceptions.
+         */
+        ICameraService cameraService = CameraServiceBinderDecorator.newInstance(cameraServiceRaw);
+
+        try {
+            CameraServiceBinderDecorator.throwOnError(
+                    CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
+        } catch (CameraRuntimeException e) {
+            handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
+        }
+
+        try {
+            cameraService.addListener(mServiceListener);
+            mCameraService = cameraService;
+        } catch(CameraRuntimeException e) {
+            // Unexpected failure
+            throw new IllegalStateException("Failed to register a camera service listener",
+                    e.asChecked());
+        } catch (RemoteException e) {
+            // Camera service is now down, leave mCameraService as null
+        }
+    }
+
+    /**
+     * Return a best-effort ICameraService.
+     *
+     * <p>This will be null if the camera service
+     * is not currently available. If the camera service has died since the last
+     * use of the camera service, will try to reconnect to the service.</p>
+     */
+    private ICameraService getCameraServiceLocked() {
+        if (mCameraService == null) {
+            Log.i(TAG, "getCameraServiceLocked: Reconnecting to camera service");
+            connectCameraServiceLocked();
+            if (mCameraService == null) {
+                Log.e(TAG, "Camera service is unavailable");
+            }
+        }
+        return mCameraService;
+    }
+
+    /**
+     * Listener for camera service death.
+     *
+     * <p>The camera service isn't supposed to die under any normal circumstances, but can be turned
+     * off during debug, or crash due to bugs.  So detect that and null out the interface object, so
+     * that the next calls to the manager can try to reconnect.</p>
+     */
+    private class CameraServiceDeathListener implements IBinder.DeathRecipient {
+        public void binderDied() {
+            synchronized(mLock) {
+                mCameraService = null;
+                // Tell listeners that the cameras are _available_, because any existing clients
+                // will have gotten disconnected. This is optimistic under the assumption that the
+                // service will be back shortly.
+                //
+                // Without this, a camera service crash while a camera is open will never signal to
+                // listeners that previously in-use cameras are now available.
+                for (String cameraId : mDeviceIdList) {
+                    mServiceListener.onStatusChangedLocked(CameraServiceListener.STATUS_PRESENT,
+                            cameraId);
+                }
+            }
         }
     }
 
@@ -595,77 +707,102 @@
             }
         }
 
+        private void postSingleUpdate(final AvailabilityListener listener, final Handler handler,
+                final String id, final int status) {
+            if (isAvailable(status)) {
+                handler.post(
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            listener.onCameraAvailable(id);
+                        }
+                    });
+            } else {
+                handler.post(
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            listener.onCameraUnavailable(id);
+                        }
+                    });
+            }
+        }
+
+        /**
+         * Send the state of all known cameras to the provided listener, to initialize
+         * the listener's knowledge of camera state.
+         */
+        public void updateListenerLocked(AvailabilityListener listener, Handler handler) {
+            for (int i = 0; i < mDeviceStatus.size(); i++) {
+                String id = mDeviceStatus.keyAt(i);
+                Integer status = mDeviceStatus.valueAt(i);
+                postSingleUpdate(listener, handler, id, status);
+            }
+        }
+
         @Override
         public void onStatusChanged(int status, int cameraId) throws RemoteException {
             synchronized(CameraManager.this.mLock) {
+                onStatusChangedLocked(status, String.valueOf(cameraId));
+            }
+        }
 
+        public void onStatusChangedLocked(int status, String id) {
+            if (DEBUG) {
                 Log.v(TAG,
-                        String.format("Camera id %d has status changed to 0x%x", cameraId, status));
+                        String.format("Camera id %s has status changed to 0x%x", id, status));
+            }
 
-                final String id = String.valueOf(cameraId);
+            if (!validStatus(status)) {
+                Log.e(TAG, String.format("Ignoring invalid device %s status 0x%x", id,
+                                status));
+                return;
+            }
 
-                if (!validStatus(status)) {
-                    Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId,
-                            status));
-                    return;
-                }
+            Integer oldStatus = mDeviceStatus.put(id, status);
 
-                Integer oldStatus = mDeviceStatus.put(id, status);
-
-                if (oldStatus != null && oldStatus == status) {
+            if (oldStatus != null && oldStatus == status) {
+                if (DEBUG) {
                     Log.v(TAG, String.format(
-                            "Device status changed to 0x%x, which is what it already was",
-                            status));
-                    return;
+                        "Device status changed to 0x%x, which is what it already was",
+                        status));
                 }
+                return;
+            }
 
-                // TODO: consider abstracting out this state minimization + transition
-                // into a separate
-                // more easily testable class
-                // i.e. (new State()).addState(STATE_AVAILABLE)
-                //                   .addState(STATE_NOT_AVAILABLE)
-                //                   .addTransition(STATUS_PRESENT, STATE_AVAILABLE),
-                //                   .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE)
-                //                   .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE);
-                //                   .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE);
+            // TODO: consider abstracting out this state minimization + transition
+            // into a separate
+            // more easily testable class
+            // i.e. (new State()).addState(STATE_AVAILABLE)
+            //                   .addState(STATE_NOT_AVAILABLE)
+            //                   .addTransition(STATUS_PRESENT, STATE_AVAILABLE),
+            //                   .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE)
+            //                   .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE);
+            //                   .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE);
 
-                // Translate all the statuses to either 'available' or 'not available'
-                //  available -> available         => no new update
-                //  not available -> not available => no new update
-                if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) {
-
+            // Translate all the statuses to either 'available' or 'not available'
+            //  available -> available         => no new update
+            //  not available -> not available => no new update
+            if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) {
+                if (DEBUG) {
                     Log.v(TAG,
                             String.format(
-                                    "Device status was previously available (%d), " +
-                                            " and is now again available (%d)" +
-                                            "so no new client visible update will be sent",
-                                    isAvailable(status), isAvailable(status)));
-                    return;
+                                "Device status was previously available (%d), " +
+                                " and is now again available (%d)" +
+                                "so no new client visible update will be sent",
+                                isAvailable(status), isAvailable(status)));
                 }
+                return;
+            }
 
-                final int listenerCount = mListenerMap.size();
-                for (int i = 0; i < listenerCount; i++) {
-                    Handler handler = mListenerMap.valueAt(i);
-                    final AvailabilityListener listener = mListenerMap.keyAt(i);
-                    if (isAvailable(status)) {
-                        handler.post(
-                            new Runnable() {
-                                @Override
-                                public void run() {
-                                    listener.onCameraAvailable(id);
-                                }
-                            });
-                    } else {
-                        handler.post(
-                            new Runnable() {
-                                @Override
-                                public void run() {
-                                    listener.onCameraUnavailable(id);
-                                }
-                            });
-                    }
-                } // for
-            } // synchronized
-        } // onStatusChanged
+            final int listenerCount = mListenerMap.size();
+            for (int i = 0; i < listenerCount; i++) {
+                Handler handler = mListenerMap.valueAt(i);
+                final AvailabilityListener listener = mListenerMap.keyAt(i);
+
+                postSingleUpdate(listener, handler, id, status);
+            }
+        } // onStatusChangedLocked
+
     } // CameraServiceListener
 } // CameraManager
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index c9774ed..20a04f0 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2242,6 +2242,33 @@
             new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class);
 
     /**
+     * <p>Noise model coefficients for each CFA mosaic channel.</p>
+     * <p>This tag contains two noise model coefficients for each CFA channel
+     * corresponding to the sensor amplification (S) and sensor readout
+     * noise (O).  These are given as pairs of coefficients for each channel
+     * in the same order as channels listed for the CFA layout tag
+     * (see {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}).  This is
+     * represented as an array of Pair&lt;Double, Double&gt;, where
+     * the first member of the Pair at index n is the S coefficient and the
+     * second member is the O coefficient for the nth color channel in the CFA.</p>
+     * <p>These coefficients are used in a two parameter noise model to describe
+     * the amount of noise present in the image for each CFA channel.  The
+     * noise model used here is:</p>
+     * <p>N(x) = sqrt(Sx + O)</p>
+     * <p>Where x represents the recorded signal of a CFA channel normalized to
+     * the range [0, 1], and S and O are the noise model coeffiecients for
+     * that channel.</p>
+     * <p>A more detailed description of the noise model can be found in the
+     * Adobe DNG specification for the NoiseProfile tag.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+     */
+    @PublicKey
+    public static final Key<android.util.Pair<Double,Double>[]> SENSOR_NOISE_PROFILE =
+            new Key<android.util.Pair<Double,Double>[]>("android.sensor.noiseProfile", new TypeReference<android.util.Pair<Double,Double>[]>() {{ }});
+
+    /**
      * <p>The worst-case divergence between Bayer green channels.</p>
      * <p>This value is an estimate of the worst case split between the
      * Bayer green channels in the red and blue rows in the sensor color
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 02be22f..ed4e457 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -28,8 +28,6 @@
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.CloseableLock;
-import android.hardware.camera2.utils.CloseableLock.ScopedLock;
 import android.hardware.camera2.utils.LongParcelable;
 import android.os.Handler;
 import android.os.IBinder;
@@ -59,7 +57,8 @@
     // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
     private ICameraDeviceUser mRemoteDevice;
 
-    private final CloseableLock mCloseLock;
+    // Lock to synchronize cross-thread access to device public interface
+    private final Object mInterfaceLock = new Object();
     private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
 
     private final StateListener mDeviceListener;
@@ -104,60 +103,64 @@
     private final Runnable mCallOnOpened = new Runnable() {
         @Override
         public void run() {
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            StateListener sessionListener = null;
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
-                StateListener sessionListener = mSessionStateListener;
-                if (sessionListener != null) {
-                    sessionListener.onOpened(CameraDeviceImpl.this);
-                }
-                mDeviceListener.onOpened(CameraDeviceImpl.this);
+                sessionListener = mSessionStateListener;
             }
+            if (sessionListener != null) {
+                sessionListener.onOpened(CameraDeviceImpl.this);
+            }
+            mDeviceListener.onOpened(CameraDeviceImpl.this);
         }
     };
 
     private final Runnable mCallOnUnconfigured = new Runnable() {
         @Override
         public void run() {
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            StateListener sessionListener = null;
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
-                StateListener sessionListener = mSessionStateListener;
-                if (sessionListener != null) {
-                    sessionListener.onUnconfigured(CameraDeviceImpl.this);
-                }
-                mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
+                sessionListener = mSessionStateListener;
             }
+            if (sessionListener != null) {
+                sessionListener.onUnconfigured(CameraDeviceImpl.this);
+            }
+            mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
         }
     };
 
     private final Runnable mCallOnActive = new Runnable() {
         @Override
         public void run() {
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            StateListener sessionListener = null;
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
-                StateListener sessionListener = mSessionStateListener;
-                if (sessionListener != null) {
-                    sessionListener.onActive(CameraDeviceImpl.this);
-                }
-                mDeviceListener.onActive(CameraDeviceImpl.this);
+                sessionListener = mSessionStateListener;
             }
+            if (sessionListener != null) {
+                sessionListener.onActive(CameraDeviceImpl.this);
+            }
+            mDeviceListener.onActive(CameraDeviceImpl.this);
         }
     };
 
     private final Runnable mCallOnBusy = new Runnable() {
         @Override
         public void run() {
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            StateListener sessionListener = null;
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
-                StateListener sessionListener = mSessionStateListener;
-                if (sessionListener != null) {
-                    sessionListener.onBusy(CameraDeviceImpl.this);
-                }
-                mDeviceListener.onBusy(CameraDeviceImpl.this);
+                sessionListener = mSessionStateListener;
             }
+            if (sessionListener != null) {
+                sessionListener.onBusy(CameraDeviceImpl.this);
+            }
+            mDeviceListener.onBusy(CameraDeviceImpl.this);
         }
     };
 
@@ -169,8 +172,10 @@
             if (mClosedOnce) {
                 throw new AssertionError("Don't post #onClosed more than once");
             }
-
-            StateListener sessionListener = mSessionStateListener;
+            StateListener sessionListener = null;
+            synchronized(mInterfaceLock) {
+                sessionListener = mSessionStateListener;
+            }
             if (sessionListener != null) {
                 sessionListener.onClosed(CameraDeviceImpl.this);
             }
@@ -182,30 +187,32 @@
     private final Runnable mCallOnIdle = new Runnable() {
         @Override
         public void run() {
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            StateListener sessionListener = null;
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
-                StateListener sessionListener = mSessionStateListener;
-                if (sessionListener != null) {
-                    sessionListener.onIdle(CameraDeviceImpl.this);
-                }
-                mDeviceListener.onIdle(CameraDeviceImpl.this);
+                sessionListener = mSessionStateListener;
             }
+            if (sessionListener != null) {
+                sessionListener.onIdle(CameraDeviceImpl.this);
+            }
+            mDeviceListener.onIdle(CameraDeviceImpl.this);
         }
     };
 
     private final Runnable mCallOnDisconnected = new Runnable() {
         @Override
         public void run() {
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            StateListener sessionListener = null;
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
-                StateListener sessionListener = mSessionStateListener;
-                if (sessionListener != null) {
-                    sessionListener.onDisconnected(CameraDeviceImpl.this);
-                }
-                mDeviceListener.onDisconnected(CameraDeviceImpl.this);
+                sessionListener = mSessionStateListener;
             }
+            if (sessionListener != null) {
+                sessionListener.onDisconnected(CameraDeviceImpl.this);
+            }
+            mDeviceListener.onDisconnected(CameraDeviceImpl.this);
         }
     };
 
@@ -218,7 +225,6 @@
         mDeviceListener = listener;
         mDeviceHandler = handler;
         mCharacteristics = characteristics;
-        mCloseLock = new CloseableLock(/*name*/"CD-" + mCameraId);
 
         final int MAX_TAG_LEN = 23;
         String tag = String.format("CameraDevice-JV-%s", mCameraId);
@@ -243,8 +249,8 @@
     }
 
     public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
-        try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-        // TODO: Move from decorator to direct binder-mediated exceptions
+        synchronized(mInterfaceLock) {
+            // TODO: Move from decorator to direct binder-mediated exceptions
             // If setRemoteFailure already called, do nothing
             if (mInError) return;
 
@@ -287,9 +293,7 @@
         }
         final int code = failureCode;
         final boolean isError = failureIsError;
-        try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-            if (scopedLock == null) return; // Camera already closed, can't go to error state
-
+        synchronized(mInterfaceLock) {
             mInError = true;
             mDeviceHandler.post(new Runnable() {
                 @Override
@@ -314,7 +318,7 @@
         if (outputs == null) {
             outputs = new ArrayList<Surface>();
         }
-        try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
+        synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
 
             HashSet<Surface> addSet = new HashSet<Surface>(outputs);    // Streams to create
@@ -378,7 +382,7 @@
     public void createCaptureSession(List<Surface> outputs,
             CameraCaptureSession.StateListener listener, Handler handler)
             throws CameraAccessException {
-        try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
+        synchronized(mInterfaceLock) {
             if (DEBUG) {
                 Log.d(TAG, "createCaptureSession");
             }
@@ -423,7 +427,7 @@
     @Override
     public CaptureRequest.Builder createCaptureRequest(int templateType)
             throws CameraAccessException {
-        try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
+        synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
 
             CameraMetadataNative templatedRequest = new CameraMetadataNative();
@@ -554,7 +558,7 @@
             }
         }
 
-        try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
+        synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
             int requestId;
 
@@ -623,7 +627,7 @@
 
     public void stopRepeating() throws CameraAccessException {
 
-        try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
+        synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
             if (mRepeatingRequestId != REQUEST_ID_NONE) {
 
@@ -654,12 +658,12 @@
 
     private void waitUntilIdle() throws CameraAccessException {
 
-        try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
+        synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
+
             if (mRepeatingRequestId != REQUEST_ID_NONE) {
                 throw new IllegalStateException("Active repeating request ongoing");
             }
-
             try {
                 mRemoteDevice.waitUntilIdle();
             } catch (CameraRuntimeException e) {
@@ -668,13 +672,11 @@
                 // impossible
                 return;
             }
-
-            mRepeatingRequestId = REQUEST_ID_NONE;
         }
     }
 
     public void flush() throws CameraAccessException {
-        try (ScopedLock scopedLock = mCloseLock.acquireExclusiveLock()) {
+        synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
 
             mDeviceHandler.post(mCallOnBusy);
@@ -697,15 +699,7 @@
 
     @Override
     public void close() {
-        mClosing = true;
-        // Acquire exclusive lock, close, release (idempotent)
-        mCloseLock.close();
-
-        /*
-         *  The rest of this is safe, since no other methods will be able to execute
-         *  (they will throw ISE instead; the callbacks will get dropped)
-         */
-        {
+        synchronized (mInterfaceLock) {
             try {
                 if (mRemoteDevice != null) {
                     mRemoteDevice.disconnect();
@@ -853,8 +847,8 @@
                 // remove request from mCaptureListenerMap
                 final int requestId = frameNumberRequestPair.getValue();
                 final CaptureListenerHolder holder;
-                try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                    if (scopedLock == null) {
+                synchronized(mInterfaceLock) {
+                    if (mRemoteDevice == null) {
                         Log.w(TAG, "Camera closed while checking sequences");
                         return;
                     }
@@ -944,8 +938,8 @@
         public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
             Runnable r = null;
 
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) {
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) {
                     return; // Camera already closed
                 }
 
@@ -985,8 +979,8 @@
             if (DEBUG) {
                 Log.d(TAG, "Camera now idle");
             }
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
                 if (!CameraDeviceImpl.this.mIdle) {
                     CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
@@ -1003,8 +997,8 @@
             }
             final CaptureListenerHolder holder;
 
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
                 // Get the listener for this frame ID, if there is one
                 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
@@ -1042,8 +1036,8 @@
                         + requestId);
             }
 
-            try (ScopedLock scopedLock = mCloseLock.acquireLock()) {
-                if (scopedLock == null) return; // Camera already closed
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
 
                 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
                 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index ab7e844..2fa9d85 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -65,7 +65,7 @@
         void onError(int errorCode, RequestHolder holder);
         void onConfiguring();
         void onIdle();
-        void onCaptureStarted(RequestHolder holder);
+        void onCaptureStarted(RequestHolder holder, long timestamp);
         void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
     }
 
@@ -125,11 +125,12 @@
      * </p>
      *
      * @param request A {@link RequestHolder} containing the request for the current capture.
+     * @param timestamp The timestamp of the capture start in nanoseconds.
      * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
      */
-    public synchronized int setCaptureStart(final RequestHolder request) {
+    public synchronized int setCaptureStart(final RequestHolder request, long timestamp) {
         mCurrentRequest = request;
-        doStateTransition(STATE_CAPTURING);
+        doStateTransition(STATE_CAPTURING, timestamp);
         return mCurrentError;
     }
 
@@ -180,6 +181,10 @@
     }
 
     private void doStateTransition(int newState) {
+        doStateTransition(newState, /*timestamp*/0);
+    }
+
+    private void doStateTransition(int newState, final long timestamp) {
         if (DEBUG) {
             if (newState != mCurrentState) {
                 Log.d(TAG, "Transitioning to state " + newState);
@@ -250,7 +255,7 @@
                     mCurrentHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            mCurrentListener.onCaptureStarted(mCurrentRequest);
+                            mCurrentListener.onCaptureStarted(mCurrentRequest, timestamp);
                         }
                     });
                 }
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 5bdef4a..c68d8c3 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -25,11 +25,15 @@
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.utils.LongParcelable;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.os.ConditionVariable;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.SparseArray;
@@ -66,14 +70,18 @@
     private final SparseArray<Surface> mSurfaces;
     private final CameraCharacteristics mCameraCharacteristics;
     private final CameraLooper mCameraInit;
+    private final CameraCallbackThread mCameraCallbacks;
+
 
     protected CameraDeviceUserShim(int cameraId, LegacyCameraDevice legacyCamera,
-            CameraCharacteristics characteristics, CameraLooper cameraInit) {
+            CameraCharacteristics characteristics, CameraLooper cameraInit,
+            CameraCallbackThread cameraCallbacks) {
         mLegacyDevice = legacyCamera;
         mConfiguring = false;
         mSurfaces = new SparseArray<Surface>();
         mCameraCharacteristics = characteristics;
         mCameraInit = cameraInit;
+        mCameraCallbacks = cameraCallbacks;
 
         mSurfaceIdCounter = 0;
     }
@@ -173,6 +181,122 @@
         }
     }
 
+    /**
+     * A thread to process callbacks to send back to the camera client.
+     *
+     * <p>This effectively emulates one-way binder semantics when in the same process as the
+     * callee.</p>
+     */
+    private static class CameraCallbackThread implements ICameraDeviceCallbacks {
+        private static final int CAMERA_ERROR = 0;
+        private static final int CAMERA_IDLE = 1;
+        private static final int CAPTURE_STARTED = 2;
+        private static final int RESULT_RECEIVED = 3;
+
+        private final HandlerThread mHandlerThread;
+        private Handler mHandler;
+
+        private final ICameraDeviceCallbacks mCallbacks;
+
+        public CameraCallbackThread(ICameraDeviceCallbacks callbacks) {
+            mCallbacks = callbacks;
+
+            mHandlerThread = new HandlerThread("LegacyCameraCallback");
+            mHandlerThread.start();
+        }
+
+        public void close() {
+            mHandlerThread.quitSafely();
+        }
+
+        @Override
+        public void onCameraError(final int errorCode, final CaptureResultExtras resultExtras) {
+            Message msg = getHandler().obtainMessage(CAMERA_ERROR,
+                /*arg1*/ errorCode, /*arg2*/ 0,
+                /*obj*/ resultExtras);
+            getHandler().sendMessage(msg);
+        }
+
+        @Override
+        public void onCameraIdle() {
+            Message msg = getHandler().obtainMessage(CAMERA_IDLE);
+            getHandler().sendMessage(msg);
+        }
+
+        @Override
+        public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
+            Message msg = getHandler().obtainMessage(CAPTURE_STARTED,
+                    /*arg1*/ (int) (timestamp & 0xFFFFFFFFL),
+                    /*arg2*/ (int) ( (timestamp >> 32) & 0xFFFFFFFFL),
+                    /*obj*/ resultExtras);
+            getHandler().sendMessage(msg);
+        }
+
+        @Override
+        public void onResultReceived(final CameraMetadataNative result,
+                final CaptureResultExtras resultExtras) {
+            Object[] resultArray = new Object[] { result, resultExtras };
+            Message msg = getHandler().obtainMessage(RESULT_RECEIVED,
+                    /*obj*/ resultArray);
+            getHandler().sendMessage(msg);
+        }
+
+        @Override
+        public IBinder asBinder() {
+            // This is solely intended to be used for in-process binding.
+            return null;
+        }
+
+        private Handler getHandler() {
+            if (mHandler == null) {
+                mHandler = new CallbackHandler(mHandlerThread.getLooper());
+            }
+            return mHandler;
+        }
+
+        private class CallbackHandler extends Handler {
+            public CallbackHandler(Looper l) {
+                super(l);
+            }
+
+            public void handleMessage(Message msg) {
+                try {
+                    switch (msg.what) {
+                        case CAMERA_ERROR: {
+                            int errorCode = msg.arg1;
+                            CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
+                            mCallbacks.onCameraError(errorCode, resultExtras);
+                            break;
+                        }
+                        case CAMERA_IDLE:
+                            mCallbacks.onCameraIdle();
+                            break;
+                        case CAPTURE_STARTED: {
+                            long timestamp = msg.arg2 & 0xFFFFFFFFL;
+                            timestamp = (timestamp << 32) | (msg.arg1 & 0xFFFFFFFFL);
+                            CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
+                            mCallbacks.onCaptureStarted(resultExtras, timestamp);
+                            break;
+                        }
+                        case RESULT_RECEIVED: {
+                            Object[] resultArray = (Object[]) msg.obj;
+                            CameraMetadataNative result = (CameraMetadataNative) resultArray[0];
+                            CaptureResultExtras resultExtras = (CaptureResultExtras) resultArray[1];
+                            mCallbacks.onResultReceived(result, resultExtras);
+                            break;
+                        }
+                        default:
+                            throw new IllegalArgumentException(
+                                "Unknown callback message " + msg.what);
+                    }
+                } catch (RemoteException e) {
+                    throw new IllegalStateException(
+                        "Received remote exception during camera callback " + msg.what, e);
+                }
+            }
+        }
+    }
+
     public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
                                                          int cameraId) {
         if (DEBUG) {
@@ -187,6 +311,8 @@
 
         CameraLooper init = new CameraLooper(cameraId);
 
+        CameraCallbackThread threadCallbacks = new CameraCallbackThread(callbacks);
+
         // TODO: Make this async instead of blocking
         int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
         Camera legacyCamera = init.getCamera();
@@ -200,8 +326,8 @@
         CameraCharacteristics characteristics =
                 LegacyMetadataMapper.createCharacteristics(legacyCamera.getParameters(), info);
         LegacyCameraDevice device = new LegacyCameraDevice(
-                cameraId, legacyCamera, characteristics, callbacks);
-        return new CameraDeviceUserShim(cameraId, device, characteristics, init);
+                cameraId, legacyCamera, characteristics, threadCallbacks);
+        return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
     }
 
     @Override
@@ -214,6 +340,7 @@
             mLegacyDevice.close();
         } finally {
             mCameraInit.close();
+            mCameraCallbacks.close();
         }
     }
 
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
new file mode 100644
index 0000000..ab31d8c
--- /dev/null
+++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.legacy;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayDeque;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Collect timestamps and state for each {@link CaptureRequest} as it passes through
+ * the Legacy camera pipeline.
+ */
+public class CaptureCollector {
+    private static final String TAG = "CaptureCollector";
+
+    private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
+
+    private static final int FLAG_RECEIVED_JPEG = 1;
+    private static final int FLAG_RECEIVED_JPEG_TS = 2;
+    private static final int FLAG_RECEIVED_PREVIEW = 4;
+    private static final int FLAG_RECEIVED_PREVIEW_TS = 8;
+    private static final int FLAG_RECEIVED_ALL_JPEG = FLAG_RECEIVED_JPEG | FLAG_RECEIVED_JPEG_TS;
+    private static final int FLAG_RECEIVED_ALL_PREVIEW = FLAG_RECEIVED_PREVIEW |
+            FLAG_RECEIVED_PREVIEW_TS;
+
+    private static final int MAX_JPEGS_IN_FLIGHT = 1;
+
+    private class CaptureHolder {
+        private final RequestHolder mRequest;
+        private final LegacyRequest mLegacy;
+        public final boolean needsJpeg;
+        public final boolean needsPreview;
+
+        private long mTimestamp = 0;
+        private int mReceivedFlags = 0;
+        private boolean mHasStarted = false;
+
+        public CaptureHolder(RequestHolder request, LegacyRequest legacyHolder) {
+            mRequest = request;
+            mLegacy = legacyHolder;
+            needsJpeg = request.hasJpegTargets();
+            needsPreview = request.hasPreviewTargets();
+        }
+
+        public boolean isPreviewCompleted() {
+            return (mReceivedFlags & FLAG_RECEIVED_ALL_PREVIEW) == FLAG_RECEIVED_ALL_PREVIEW;
+        }
+
+        public  boolean isJpegCompleted() {
+            return (mReceivedFlags & FLAG_RECEIVED_ALL_JPEG) == FLAG_RECEIVED_ALL_JPEG;
+        }
+
+        public boolean isCompleted() {
+            return (needsJpeg == isJpegCompleted()) && (needsPreview == isPreviewCompleted());
+        }
+
+        public void tryComplete() {
+            if (isCompleted()) {
+                if (needsPreview && isPreviewCompleted()) {
+                    CaptureCollector.this.onPreviewCompleted();
+                }
+                CaptureCollector.this.onRequestCompleted(mRequest, mLegacy, mTimestamp);
+            }
+        }
+
+        public void setJpegTimestamp(long timestamp) {
+            if (DEBUG) {
+                Log.d(TAG, "setJpegTimestamp - called for request " + mRequest.getRequestId());
+            }
+            if (!needsJpeg) {
+                throw new IllegalStateException(
+                        "setJpegTimestamp called for capture with no jpeg targets.");
+            }
+            if (isCompleted()) {
+                throw new IllegalStateException(
+                        "setJpegTimestamp called on already completed request.");
+            }
+
+            mReceivedFlags |= FLAG_RECEIVED_JPEG_TS;
+
+            if (mTimestamp == 0) {
+                mTimestamp = timestamp;
+            }
+
+            if (!mHasStarted) {
+                mHasStarted = true;
+                CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp);
+            }
+
+            tryComplete();
+        }
+
+        public void setJpegProduced() {
+            if (DEBUG) {
+                Log.d(TAG, "setJpegProduced - called for request " + mRequest.getRequestId());
+            }
+            if (!needsJpeg) {
+                throw new IllegalStateException(
+                        "setJpegProduced called for capture with no jpeg targets.");
+            }
+            if (isCompleted()) {
+                throw new IllegalStateException(
+                        "setJpegProduced called on already completed request.");
+            }
+
+            mReceivedFlags |= FLAG_RECEIVED_JPEG;
+            tryComplete();
+        }
+
+        public void setPreviewTimestamp(long timestamp) {
+            if (DEBUG) {
+                Log.d(TAG, "setPreviewTimestamp - called for request " + mRequest.getRequestId());
+            }
+            if (!needsPreview) {
+                throw new IllegalStateException(
+                        "setPreviewTimestamp called for capture with no preview targets.");
+            }
+            if (isCompleted()) {
+                throw new IllegalStateException(
+                        "setPreviewTimestamp called on already completed request.");
+            }
+
+            mReceivedFlags |= FLAG_RECEIVED_PREVIEW_TS;
+
+            if (mTimestamp == 0) {
+                mTimestamp = timestamp;
+            }
+
+            if (!needsJpeg) {
+                if (!mHasStarted) {
+                    mHasStarted = true;
+                    CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp);
+                }
+            }
+
+            tryComplete();
+        }
+
+        public void setPreviewProduced() {
+            if (DEBUG) {
+                Log.d(TAG, "setPreviewProduced - called for request " + mRequest.getRequestId());
+            }
+            if (!needsPreview) {
+                throw new IllegalStateException(
+                        "setPreviewProduced called for capture with no preview targets.");
+            }
+            if (isCompleted()) {
+                throw new IllegalStateException(
+                        "setPreviewProduced called on already completed request.");
+            }
+
+            mReceivedFlags |= FLAG_RECEIVED_PREVIEW;
+            tryComplete();
+        }
+    }
+
+    private final ArrayDeque<CaptureHolder> mJpegCaptureQueue;
+    private final ArrayDeque<CaptureHolder> mJpegProduceQueue;
+    private final ArrayDeque<CaptureHolder> mPreviewCaptureQueue;
+    private final ArrayDeque<CaptureHolder> mPreviewProduceQueue;
+
+    private final ReentrantLock mLock = new ReentrantLock();
+    private final Condition mIsEmpty;
+    private final Condition mPreviewsEmpty;
+    private final Condition mNotFull;
+    private final CameraDeviceState mDeviceState;
+    private final LegacyResultMapper mMapper = new LegacyResultMapper();
+    private int mInFlight = 0;
+    private int mInFlightPreviews = 0;
+    private final int mMaxInFlight;
+
+    /**
+     * Create a new {@link CaptureCollector} that can modify the given {@link CameraDeviceState}.
+     *
+     * @param maxInFlight max allowed in-flight requests.
+     * @param deviceState the {@link CameraDeviceState} to update as requests are processed.
+     */
+    public CaptureCollector(int maxInFlight, CameraDeviceState deviceState) {
+        mMaxInFlight = maxInFlight;
+        mJpegCaptureQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT);
+        mJpegProduceQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT);
+        mPreviewCaptureQueue = new ArrayDeque<>(mMaxInFlight);
+        mPreviewProduceQueue = new ArrayDeque<>(mMaxInFlight);
+        mIsEmpty = mLock.newCondition();
+        mNotFull = mLock.newCondition();
+        mPreviewsEmpty = mLock.newCondition();
+        mDeviceState = deviceState;
+    }
+
+    /**
+     * Queue a new request.
+     *
+     * <p>
+     * For requests that use the Camera1 API preview output stream, this will block if there are
+     * already {@code maxInFlight} requests in progress (until at least one prior request has
+     * completed). For requests that use the Camera1 API jpeg callbacks, this will block until
+     * all prior requests have been completed to avoid stopping preview for
+     * {@link android.hardware.Camera#takePicture} before prior preview requests have been
+     * completed.
+     * </p>
+     * @param holder the {@link RequestHolder} for this request.
+     * @param legacy the {@link LegacyRequest} for this request; this will not be mutated.
+     * @param timeout a timeout to use for this call.
+     * @param unit the units to use for the timeout.
+     * @return {@code false} if this method timed out.
+     * @throws InterruptedException if this thread is interrupted.
+     */
+    public boolean queueRequest(RequestHolder holder, LegacyRequest legacy, long timeout,
+                                TimeUnit unit)
+            throws InterruptedException {
+        CaptureHolder h = new CaptureHolder(holder, legacy);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            if (DEBUG) {
+                Log.d(TAG, "queueRequest  for request " + holder.getRequestId() +
+                        " - " + mInFlight + " requests remain in flight.");
+            }
+            if (h.needsJpeg) {
+                // Wait for all current requests to finish before queueing jpeg.
+                while (mInFlight > 0) {
+                    if (nanos <= 0) {
+                        return false;
+                    }
+                    nanos = mIsEmpty.awaitNanos(nanos);
+                }
+                mJpegCaptureQueue.add(h);
+                mJpegProduceQueue.add(h);
+            }
+            if (h.needsPreview) {
+                while (mInFlight >= mMaxInFlight) {
+                    if (nanos <= 0) {
+                        return false;
+                    }
+                    nanos = mNotFull.awaitNanos(nanos);
+                }
+                mPreviewCaptureQueue.add(h);
+                mPreviewProduceQueue.add(h);
+                mInFlightPreviews++;
+            }
+
+            if (!(h.needsJpeg || h.needsPreview)) {
+                throw new IllegalStateException("Request must target at least one output surface!");
+            }
+
+            mInFlight++;
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Wait all queued requests to complete.
+     *
+     * @param timeout a timeout to use for this call.
+     * @param unit the units to use for the timeout.
+     * @return {@code false} if this method timed out.
+     * @throws InterruptedException if this thread is interrupted.
+     */
+    public boolean waitForEmpty(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            while (mInFlight > 0) {
+                if (nanos <= 0) {
+                    return false;
+                }
+                nanos = mIsEmpty.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Wait all queued requests that use the Camera1 API preview output to complete.
+     *
+     * @param timeout a timeout to use for this call.
+     * @param unit the units to use for the timeout.
+     * @return {@code false} if this method timed out.
+     * @throws InterruptedException if this thread is interrupted.
+     */
+    public boolean waitForPreviewsEmpty(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            while (mInFlightPreviews > 0) {
+                if (nanos <= 0) {
+                    return false;
+                }
+                nanos = mPreviewsEmpty.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Called to alert the {@link CaptureCollector} that the jpeg capture has begun.
+     *
+     * @param timestamp the time of the jpeg capture.
+     * @return the {@link RequestHolder} for the request associated with this capture.
+     */
+    public RequestHolder jpegCaptured(long timestamp) {
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            CaptureHolder h = mJpegCaptureQueue.poll();
+            if (h == null) {
+                Log.w(TAG, "jpegCaptured called with no jpeg request on queue!");
+                return null;
+            }
+            h.setJpegTimestamp(timestamp);
+            return h.mRequest;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Called to alert the {@link CaptureCollector} that the jpeg capture has completed.
+     *
+     * @return a pair containing the {@link RequestHolder} and the timestamp of the capture.
+     */
+    public Pair<RequestHolder, Long> jpegProduced() {
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            CaptureHolder h = mJpegProduceQueue.poll();
+            if (h == null) {
+                Log.w(TAG, "jpegProduced called with no jpeg request on queue!");
+                return null;
+            }
+            h.setJpegProduced();
+            return new Pair<>(h.mRequest, h.mTimestamp);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Check if there are any pending capture requests that use the Camera1 API preview output.
+     *
+     * @return {@code true} if there are pending preview requests.
+     */
+    public boolean hasPendingPreviewCaptures() {
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            return !mPreviewCaptureQueue.isEmpty();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Called to alert the {@link CaptureCollector} that the preview capture has begun.
+     *
+     * @param timestamp the time of the preview capture.
+     * @return a pair containing the {@link RequestHolder} and the timestamp of the capture.
+     */
+    public Pair<RequestHolder, Long> previewCaptured(long timestamp) {
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            CaptureHolder h = mPreviewCaptureQueue.poll();
+            if (h == null) {
+                Log.w(TAG, "previewCaptured called with no preview request on queue!");
+                return null;
+            }
+            h.setPreviewTimestamp(timestamp);
+            return new Pair<>(h.mRequest, h.mTimestamp);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Called to alert the {@link CaptureCollector} that the preview capture has completed.
+     *
+     * @return the {@link RequestHolder} for the request associated with this capture.
+     */
+    public RequestHolder previewProduced() {
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            CaptureHolder h = mPreviewProduceQueue.poll();
+            if (h == null) {
+                Log.w(TAG, "previewProduced called with no preview request on queue!");
+                return null;
+            }
+            h.setPreviewProduced();
+            return h.mRequest;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    private void onPreviewCompleted() {
+        mInFlightPreviews--;
+        if (mInFlightPreviews < 0) {
+            throw new IllegalStateException(
+                    "More preview captures completed than requests queued.");
+        }
+        if (mInFlightPreviews == 0) {
+            mPreviewsEmpty.signalAll();
+        }
+    }
+
+    private void onRequestCompleted(RequestHolder request, LegacyRequest legacyHolder,
+                                    long timestamp) {
+        mInFlight--;
+        if (DEBUG) {
+            Log.d(TAG, "Completed request " + request.getRequestId() +
+                    ", " + mInFlight + " requests remain in flight.");
+        }
+        if (mInFlight < 0) {
+            throw new IllegalStateException(
+                    "More captures completed than requests queued.");
+        }
+        mNotFull.signalAll();
+        if (mInFlight == 0) {
+            mIsEmpty.signalAll();
+        }
+        CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
+                legacyHolder, timestamp);
+        mDeviceState.setCaptureResult(request, result);
+    }
+}
diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
index 5d44fd2..06521cf 100644
--- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
@@ -25,6 +25,8 @@
 
 import java.util.Collection;
 
+import static com.android.internal.util.Preconditions.*;
+
 /**
  * GLThreadManager handles the thread used for rendering into the configured output surfaces.
  */
@@ -38,6 +40,8 @@
     private static final int MSG_DROP_FRAMES = 4;
     private static final int MSG_ALLOW_FRAMES = 5;
 
+    private CaptureCollector mCaptureCollector;
+
     private final SurfaceTextureRenderer mTextureRenderer;
 
     private final RequestHandlerThread mGLHandlerThread;
@@ -51,10 +55,13 @@
     private static class ConfigureHolder {
         public final ConditionVariable condition;
         public final Collection<Surface> surfaces;
+        public final CaptureCollector collector;
 
-        public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces) {
+        public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces,
+                               CaptureCollector collector) {
             this.condition = condition;
             this.surfaces = surfaces;
+            this.collector = collector;
         }
     }
 
@@ -74,6 +81,7 @@
                     ConfigureHolder configure = (ConfigureHolder) msg.obj;
                     mTextureRenderer.cleanupEGLContext();
                     mTextureRenderer.configureSurfaces(configure.surfaces);
+                    mCaptureCollector = checkNotNull(configure.collector);
                     configure.condition.open();
                     mConfigured = true;
                     break;
@@ -88,7 +96,7 @@
                     if (!mConfigured) {
                         Log.e(TAG, "Dropping frame, EGL context not configured!");
                     }
-                    mTextureRenderer.drawIntoSurfaces((Collection<Surface>) msg.obj);
+                    mTextureRenderer.drawIntoSurfaces(mCaptureCollector);
                     break;
                 case MSG_CLEANUP:
                     mTextureRenderer.cleanupEGLContext();
@@ -158,16 +166,11 @@
     }
 
     /**
-     * Queue a new call to draw into a given set of surfaces.
-     *
-     * <p>
-     * The set of surfaces passed here must be a subset of the set of surfaces passed in
-     * the last call to {@link #setConfigurationAndWait}.
-     * </p>
-     *
-     * @param targets a collection of {@link android.view.Surface}s to draw into.
+     * Queue a new call to draw into the surfaces specified in the next available preview
+     * request from the {@link CaptureCollector} passed to
+     * {@link #setConfigurationAndWait(java.util.Collection, CaptureCollector)};
      */
-    public void queueNewFrame(Collection<Surface> targets) {
+    public void queueNewFrame() {
         Handler handler = mGLHandlerThread.getHandler();
 
         /**
@@ -175,7 +178,7 @@
          * are produced, drop frames rather than allowing the queue to back up.
          */
         if (!handler.hasMessages(MSG_NEW_FRAME)) {
-            handler.sendMessage(handler.obtainMessage(MSG_NEW_FRAME, targets));
+            handler.sendMessage(handler.obtainMessage(MSG_NEW_FRAME));
         } else {
             Log.e(TAG, "GLThread dropping frame.  Not consuming frames quickly enough!");
         }
@@ -186,12 +189,14 @@
      * this configuration has been applied.
      *
      * @param surfaces a collection of {@link android.view.Surface}s to configure.
+     * @param collector a {@link CaptureCollector} to retrieve requests from.
      */
-    public void setConfigurationAndWait(Collection<Surface> surfaces) {
+    public void setConfigurationAndWait(Collection<Surface> surfaces, CaptureCollector collector) {
+        checkNotNull(collector, "collector must not be null");
         Handler handler = mGLHandlerThread.getHandler();
 
         final ConditionVariable condition = new ConditionVariable(/*closed*/false);
-        ConfigureHolder configure = new ConfigureHolder(condition, surfaces);
+        ConfigureHolder configure = new ConfigureHolder(condition, surfaces, collector);
 
         Message m = handler.obtainMessage(MSG_NEW_CONFIGURATION, /*arg1*/0, /*arg2*/0, configure);
         handler.sendMessage(m);
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 71d3d4b..cbf4a3d 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -135,10 +135,9 @@
         }
 
         @Override
-        public void onCaptureStarted(RequestHolder holder) {
+        public void onCaptureStarted(RequestHolder holder, final long timestamp) {
             final CaptureResultExtras extras = getExtrasFromRequest(holder);
 
-            final long timestamp = System.nanoTime();
             mResultHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -146,7 +145,6 @@
                         Log.d(TAG, "doing onCaptureStarted callback.");
                     }
                     try {
-                        // TODO: Don't fake timestamp
                         mDeviceCallbacks.onCaptureStarted(extras, timestamp);
                     } catch (RemoteException e) {
                         throw new IllegalStateException(
@@ -167,7 +165,6 @@
                         Log.d(TAG, "doing onCaptureResult callback.");
                     }
                     try {
-                        // TODO: Don't fake metadata
                         mDeviceCallbacks.onResultReceived(result, extras);
                     } catch (RemoteException e) {
                         throw new IllegalStateException(
@@ -483,6 +480,12 @@
         return new Size(dimens[0], dimens[1]);
     }
 
+    static void setNextTimestamp(Surface surface, long timestamp)
+            throws BufferQueueAbandonedException {
+        checkNotNull(surface);
+        LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
+    }
+
     private static native int nativeDetectSurfaceType(Surface surface);
 
     private static native int nativeDetectSurfaceDimens(Surface surface,
@@ -506,4 +509,5 @@
     private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
             /*out*/int[/*2*/] dimens);
 
+    private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
 }
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index cc7a90e..066b416 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -38,6 +38,8 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
 import static com.android.internal.util.Preconditions.*;
 
@@ -62,22 +64,20 @@
     private final CameraCharacteristics mCharacteristics;
 
     private final CameraDeviceState mDeviceState;
+    private final CaptureCollector mCaptureCollector;
 
     private static final int MSG_CONFIGURE_OUTPUTS = 1;
     private static final int MSG_SUBMIT_CAPTURE_REQUEST = 2;
     private static final int MSG_CLEANUP = 3;
 
+    private static final int MAX_IN_FLIGHT_REQUESTS = 2;
+
     private static final int PREVIEW_FRAME_TIMEOUT = 300; // ms
     private static final int JPEG_FRAME_TIMEOUT = 3000; // ms (same as CTS for API2)
 
     private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
     private boolean mPreviewRunning = false;
 
-    private volatile long mLastJpegTimestamp;
-    private volatile long mLastPreviewTimestamp;
-    private volatile RequestHolder mInFlightPreview;
-    private volatile RequestHolder mInFlightJpeg;
-
     private final List<Surface> mPreviewOutputs = new ArrayList<>();
     private final List<Surface> mCallbackOutputs = new ArrayList<>();
     private GLThreadManager mGLThreadManager;
@@ -167,16 +167,16 @@
     }
 
     private final ConditionVariable mReceivedJpeg = new ConditionVariable(false);
-    private final ConditionVariable mReceivedPreview = new ConditionVariable(false);
 
     private final Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
         @Override
         public void onPictureTaken(byte[] data, Camera camera) {
             Log.i(TAG, "Received jpeg.");
-            RequestHolder holder = mInFlightJpeg;
+            Pair<RequestHolder, Long> captureInfo = mCaptureCollector.jpegProduced();
+            RequestHolder holder = captureInfo.first;
+            long timestamp = captureInfo.second;
             if (holder == null) {
-                Log.w(TAG, "Dropping jpeg frame.");
-                mInFlightJpeg = null;
+                Log.e(TAG, "Dropping jpeg frame.");
                 return;
             }
             for (Surface s : holder.getHolderTargets()) {
@@ -184,6 +184,7 @@
                     if (RequestHolder.jpegType(s)) {
                         Log.i(TAG, "Producing jpeg buffer...");
                         LegacyCameraDevice.setSurfaceDimens(s, data.length, /*height*/1);
+                        LegacyCameraDevice.setNextTimestamp(s, timestamp);
                         LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1,
                                 CameraMetadataNative.NATIVE_JPEG_FORMAT);
                     }
@@ -191,6 +192,7 @@
                     Log.w(TAG, "Surface abandoned, dropping frame. ", e);
                 }
             }
+
             mReceivedJpeg.open();
         }
     };
@@ -198,7 +200,7 @@
     private final Camera.ShutterCallback mJpegShutterCallback = new Camera.ShutterCallback() {
         @Override
         public void onShutter() {
-            mLastJpegTimestamp = SystemClock.elapsedRealtimeNanos();
+            mCaptureCollector.jpegCaptured(SystemClock.elapsedRealtimeNanos());
         }
     };
 
@@ -206,29 +208,10 @@
             new SurfaceTexture.OnFrameAvailableListener() {
                 @Override
                 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
-                    RequestHolder holder = mInFlightPreview;
-
                     if (DEBUG) {
                         mPrevCounter.countAndLog();
                     }
-
-                    if (holder == null) {
-                        mGLThreadManager.queueNewFrame(null);
-                        Log.w(TAG, "Dropping preview frame.");
-                        return;
-                    }
-
-                    mInFlightPreview = null;
-
-                    if (holder.hasPreviewTargets()) {
-                        mGLThreadManager.queueNewFrame(holder.getHolderTargets());
-                    }
-
-                    /**
-                     * TODO: Get timestamp from GL thread after buffer update.
-                     */
-                    mLastPreviewTimestamp = surfaceTexture.getTimestamp();
-                    mReceivedPreview.open();
+                    mGLThreadManager.queueNewFrame();
                 }
             };
 
@@ -256,14 +239,11 @@
             mCamera.setPreviewTexture(mDummyTexture);
             startPreview();
         }
-        mInFlightJpeg = request;
-        // TODO: Hook up shutter callback to CameraDeviceStateListener#onCaptureStarted
         mCamera.takePicture(mJpegShutterCallback, /*raw*/null, mJpegCallback);
         mPreviewRunning = false;
     }
 
     private void doPreviewCapture(RequestHolder request) throws IOException {
-        mInFlightPreview = request;
         if (mPreviewRunning) {
             return; // Already running
         }
@@ -290,8 +270,6 @@
         mPreviewOutputs.clear();
         mCallbackOutputs.clear();
         mPreviewTexture = null;
-        mInFlightPreview = null;
-        mInFlightJpeg = null;
 
         int facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING);
         int orientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
@@ -389,7 +367,7 @@
             mGLThreadManager.start();
         }
         mGLThreadManager.waitUntilStarted();
-        mGLThreadManager.setConfigurationAndWait(mPreviewOutputs);
+        mGLThreadManager.setConfigurationAndWait(mPreviewOutputs, mCaptureCollector);
         mGLThreadManager.allowNewFrames();
         mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture();
         if (mPreviewTexture != null) {
@@ -553,6 +531,18 @@
                     int sizes = config.surfaces != null ? config.surfaces.size() : 0;
                     Log.i(TAG, "Configure outputs: " + sizes +
                             " surfaces configured.");
+
+                    try {
+                        boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT,
+                                TimeUnit.MILLISECONDS);
+                        if (!success) {
+                            Log.e(TAG, "Timed out while queueing configure request.");
+                        }
+                    } catch (InterruptedException e) {
+                        // TODO: report error to CameraDevice
+                        Log.e(TAG, "Interrupted while waiting for requests to complete.");
+                    }
+
                     try {
                         configureOutputs(config.surfaces);
                     } catch (IOException e) {
@@ -571,6 +561,16 @@
                     // Get the next burst from the request queue.
                     Pair<BurstHolder, Long> nextBurst = mRequestQueue.getNext();
                     if (nextBurst == null) {
+                        try {
+                            boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT,
+                                    TimeUnit.MILLISECONDS);
+                            if (!success) {
+                                Log.e(TAG, "Timed out while waiting for empty.");
+                            }
+                        } catch (InterruptedException e) {
+                            // TODO: report error to CameraDevice
+                            Log.e(TAG, "Interrupted while waiting for requests to complete.");
+                        }
                         mDeviceState.setIdle();
                         stopPreview();
                         break;
@@ -603,39 +603,41 @@
                             if (!mParams.same(legacyRequest.parameters)) {
                                 mParams = legacyRequest.parameters;
                                 mCamera.setParameters(mParams);
+
                                 paramsChanged = true;
                             }
                         }
 
-                        mDeviceState.setCaptureStart(holder);
-                        long timestamp = 0;
                         try {
+                            boolean success = mCaptureCollector.queueRequest(holder,
+                                    mLastRequest, JPEG_FRAME_TIMEOUT, TimeUnit.MILLISECONDS);
+
+                            if (!success) {
+                                Log.e(TAG, "Timed out while queueing capture request.");
+                            }
                             if (holder.hasPreviewTargets()) {
-                                mReceivedPreview.close();
                                 doPreviewCapture(holder);
-                                if (!mReceivedPreview.block(PREVIEW_FRAME_TIMEOUT)) {
-                                    // TODO: report error to CameraDevice
-                                    Log.e(TAG, "Hit timeout for preview callback!");
-                                }
-                                timestamp = mLastPreviewTimestamp;
                             }
                             if (holder.hasJpegTargets()) {
+                                success = mCaptureCollector.
+                                        waitForPreviewsEmpty(PREVIEW_FRAME_TIMEOUT *
+                                                MAX_IN_FLIGHT_REQUESTS, TimeUnit.MILLISECONDS);
+                                if (!success) {
+                                    Log.e(TAG, "Timed out waiting for prior requests to complete.");
+                                }
                                 mReceivedJpeg.close();
                                 doJpegCapture(holder);
                                 if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
                                     // TODO: report error to CameraDevice
                                     Log.e(TAG, "Hit timeout for jpeg callback!");
                                 }
-                                mInFlightJpeg = null;
-                                timestamp = mLastJpegTimestamp;
                             }
                         } catch (IOException e) {
-                            // TODO: err handling
+                            // TODO: report error to CameraDevice
                             throw new IOError(e);
-                        }
-
-                        if (timestamp == 0) {
-                            timestamp = SystemClock.elapsedRealtimeNanos();
+                        } catch (InterruptedException e) {
+                            // TODO: report error to CameraDevice
+                            Log.e(TAG, "Interrupted during capture.", e);
                         }
 
                         if (paramsChanged) {
@@ -647,11 +649,6 @@
                             // Update parameters to the latest that we think the camera is using
                             mLastRequest.setParameters(mParams);
                         }
-
-
-                        CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
-                                mLastRequest, timestamp);
-                        mDeviceState.setCaptureResult(holder, result);
                     }
                     if (DEBUG) {
                         long totalTime = SystemClock.elapsedRealtimeNanos() - startTime;
@@ -661,6 +658,16 @@
                     break;
                 case MSG_CLEANUP:
                     mCleanup = true;
+                    try {
+                        boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT,
+                                TimeUnit.MILLISECONDS);
+                        if (!success) {
+                            Log.e(TAG, "Timed out while queueing cleanup request.");
+                        }
+                    } catch (InterruptedException e) {
+                        // TODO: report error to CameraDevice
+                        Log.e(TAG, "Interrupted while waiting for requests to complete.");
+                    }
                     if (mGLThreadManager != null) {
                         mGLThreadManager.quit();
                     }
@@ -693,6 +700,7 @@
         String name = String.format("RequestThread-%d", cameraId);
         TAG = name;
         mDeviceState = checkNotNull(deviceState, "deviceState must not be null");
+        mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState);
         mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb);
     }
 
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index fdf9ba0..0687264 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -28,6 +28,7 @@
 import android.opengl.Matrix;
 import android.text.format.Time;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Size;
 import android.view.Surface;
 import android.os.SystemProperties;
@@ -599,41 +600,63 @@
 
     /**
      * Draw the current buffer in the {@link SurfaceTexture} returned from
-     * {@link #getSurfaceTexture()} into the given set of target surfaces.
+     * {@link #getSurfaceTexture()} into the set of target {@link Surface}s
+     * in the next request from the given {@link CaptureCollector}, or drop
+     * the frame if none is available.
      *
      * <p>
-     * The given surfaces must be a subset of the surfaces set in the last
-     * {@link #configureSurfaces(java.util.Collection)} call.
+     * Any {@link Surface}s targeted must be a subset of the {@link Surface}s
+     * set in the last {@link #configureSurfaces(java.util.Collection)} call.
      * </p>
      *
-     * @param targetSurfaces the surfaces to draw to.
+     * @param targetCollector the surfaces to draw to.
      */
-    public void drawIntoSurfaces(Collection<Surface> targetSurfaces) {
+    public void drawIntoSurfaces(CaptureCollector targetCollector) {
         if ((mSurfaces == null || mSurfaces.size() == 0)
                 && (mConversionSurfaces == null || mConversionSurfaces.size() == 0)) {
             return;
         }
 
+        boolean doTiming = targetCollector.hasPendingPreviewCaptures();
         checkGlError("before updateTexImage");
 
-        if (targetSurfaces == null) {
-            mSurfaceTexture.updateTexImage();
-            return;
+        if (doTiming) {
+            beginGlTiming();
         }
 
-        beginGlTiming();
-
         mSurfaceTexture.updateTexImage();
 
         long timestamp = mSurfaceTexture.getTimestamp();
-        addGlTimestamp(timestamp);
+
+        Pair<RequestHolder, Long> captureHolder = targetCollector.previewCaptured(timestamp);
+
+        // No preview request queued, drop frame.
+        if (captureHolder == null) {
+            Log.w(TAG, "Dropping preview frame.");
+            if (doTiming) {
+                endGlTiming();
+            }
+            return;
+        }
+
+        RequestHolder request = captureHolder.first;
+
+        Collection<Surface> targetSurfaces = request.getHolderTargets();
+        if (doTiming) {
+            addGlTimestamp(timestamp);
+        }
 
         List<Long> targetSurfaceIds = LegacyCameraDevice.getSurfaceIds(targetSurfaces);
         for (EGLSurfaceHolder holder : mSurfaces) {
             if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
                 makeCurrent(holder.eglSurface);
-                drawFrame(mSurfaceTexture, holder.width, holder.height);
-                swapBuffers(holder.eglSurface);
+                try {
+                    LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
+                    drawFrame(mSurfaceTexture, holder.width, holder.height);
+                    swapBuffers(holder.eglSurface);
+                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                    Log.w(TAG, "Surface abandoned, dropping frame. ", e);
+                }
             }
         }
         for (EGLSurfaceHolder holder : mConversionSurfaces) {
@@ -647,6 +670,7 @@
 
                 try {
                     int format = LegacyCameraDevice.detectSurfaceType(holder.surface);
+                    LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
                     LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(),
                             holder.width, holder.height, format);
                     swapBuffers(holder.eglSurface);
@@ -655,8 +679,11 @@
                 }
             }
         }
+        targetCollector.previewProduced();
 
-        endGlTiming();
+        if (doTiming) {
+            endGlTiming();
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 898c746..83ebadd 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -28,7 +28,7 @@
 import java.lang.reflect.Method;
 
 /**
- * Translate camera service status_t return values into exceptions.
+ * Translate camera device status_t return values into exceptions.
  *
  * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
  * @hide
@@ -57,7 +57,7 @@
     public static final int EUSERS = -87;
 
 
-    private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
+    static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
 
         @Override
         public void onBeforeInvocation(Method m, Object[] args) {
@@ -76,10 +76,9 @@
         public boolean onCatchException(Method m, Object[] args, Throwable t) {
 
             if (t instanceof DeadObjectException) {
-                UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                        CAMERA_DISCONNECTED,
+                throw new CameraRuntimeException(CAMERA_DISCONNECTED,
                         "Process hosting the camera service has died unexpectedly",
-                        t));
+                        t);
             } else if (t instanceof RemoteException) {
                 throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
                         " which should never happen.", t);
@@ -112,26 +111,20 @@
             case BAD_VALUE:
                 throw new IllegalArgumentException("Bad argument passed to camera service");
             case DEAD_OBJECT:
-                UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                        CAMERA_DISCONNECTED));
+                throw new CameraRuntimeException(CAMERA_DISCONNECTED);
             case EACCES:
-                UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                        CAMERA_DISABLED));
+                throw new CameraRuntimeException(CAMERA_DISABLED);
             case EBUSY:
-                UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                        CAMERA_IN_USE));
+                throw new CameraRuntimeException(CAMERA_IN_USE);
             case EUSERS:
-                UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                        MAX_CAMERAS_IN_USE));
+                throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
             case ENODEV:
-                UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                        CAMERA_DISCONNECTED));
+                throw new CameraRuntimeException(CAMERA_DISCONNECTED);
             case EOPNOTSUPP:
-                UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                        CAMERA_DEPRECATED_HAL));
+                throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
             case INVALID_OPERATION:
-                UncheckedThrow.throwAnyException(new IllegalStateException(
-                        "Illegal state encountered in camera service."));
+                throw new IllegalStateException(
+                        "Illegal state encountered in camera service.");
         }
 
         /**
diff --git a/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java
new file mode 100644
index 0000000..c1fb6b1
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.utils;
+
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.reflect.Method;
+
+/**
+ * Translate camera service status_t return values into exceptions.
+ *
+ * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
+ * @hide
+ */
+public class CameraServiceBinderDecorator extends CameraBinderDecorator {
+
+    private static final String TAG = "CameraServiceBinderDecorator";
+
+    static class CameraServiceBinderDecoratorListener
+            extends CameraBinderDecorator.CameraBinderDecoratorListener {
+
+        // Pass through remote exceptions, unlike CameraBinderDecorator
+        @Override
+        public boolean onCatchException(Method m, Object[] args, Throwable t) {
+
+            if (t instanceof DeadObjectException) {
+                // Can sometimes happen (camera service died)
+                // Pass on silently
+            } else if (t instanceof RemoteException) {
+                // Some other kind of remote exception - this is not normal, so let's at least
+                // note it before moving on
+                Log.e(TAG, "Unexpected RemoteException from camera service call.", t);
+            }
+            // All other exceptions also get sent onward
+            return false;
+        }
+
+    }
+
+    /**
+     * <p>
+     * Wraps the type T with a proxy that will check 'status_t' return codes
+     * from the native side of the camera service, and throw Java exceptions
+     * automatically based on the code.
+     * </p>
+     *
+     * @param obj object that will serve as the target for all method calls
+     * @param <T> the type of the element you want to wrap. This must be an interface.
+     * @return a proxy that will intercept all invocations to obj
+     */
+    public static <T> T newInstance(T obj) {
+        return Decorator.<T> newInstance(obj, new CameraServiceBinderDecoratorListener());
+    }
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index ce7a2a4..5397d49 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -487,6 +487,8 @@
      * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
      * or {@link #VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE}.
      * @param callbacks Callbacks to call when the state of the {@link VirtualDisplay} changes
+     * @param handler The handler on which the listener should be invoked, or null
+     * if the listener should be invoked on the calling thread's looper.
      * @return The newly created virtual display, or null if the application could
      * not create the virtual display.
      *
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
index acf92f1..d663714 100644
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
@@ -67,6 +67,7 @@
     // are immutable value.
     private final int mLogicalAddress;
     private final int mPhysicalAddress;
+    private final int mPortId;
     private final int mDeviceType;
     private final int mVendorId;
     private final String mDisplayName;
@@ -80,11 +81,12 @@
                 public HdmiCecDeviceInfo createFromParcel(Parcel source) {
                     int logicalAddress = source.readInt();
                     int physicalAddress = source.readInt();
+                    int portId = source.readInt();
                     int deviceType = source.readInt();
                     int vendorId = source.readInt();
                     String displayName = source.readString();
-                    return new HdmiCecDeviceInfo(logicalAddress, physicalAddress, deviceType,
-                            vendorId, displayName);
+                    return new HdmiCecDeviceInfo(logicalAddress, physicalAddress, portId,
+                            deviceType, vendorId, displayName);
                 }
 
                 @Override
@@ -98,15 +100,17 @@
      *
      * @param logicalAddress logical address of HDMI-CEC device
      * @param physicalAddress physical address of HDMI-CEC device
+     * @param portId HDMI port ID (1 for HDMI1)
      * @param deviceType type of device
      * @param vendorId vendor id of device. Used for vendor specific command.
      * @param displayName name of device
      * @hide
      */
-    public HdmiCecDeviceInfo(int logicalAddress, int physicalAddress, int deviceType,
+    public HdmiCecDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType,
             int vendorId, String displayName) {
         mLogicalAddress = logicalAddress;
         mPhysicalAddress = physicalAddress;
+        mPortId = portId;
         mDeviceType = deviceType;
         mDisplayName = displayName;
         mVendorId = vendorId;
@@ -127,6 +131,13 @@
     }
 
     /**
+     * Return the port ID.
+     */
+    public int getPortId() {
+        return mPortId;
+    }
+
+    /**
      * Return type of the device. For more details, refer constants between
      * {@link DEVICE_TV} and {@link DEVICE_INACTIVE}.
      */
@@ -179,6 +190,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mLogicalAddress);
         dest.writeInt(mPhysicalAddress);
+        dest.writeInt(mPortId);
         dest.writeInt(mDeviceType);
         dest.writeInt(mVendorId);
         dest.writeString(mDisplayName);
@@ -189,6 +201,7 @@
         StringBuffer s = new StringBuffer();
         s.append("logical_address: ").append(mLogicalAddress).append(", ");
         s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+        s.append("port_id: ").append(mPortId).append(", ");
         s.append("device_type: ").append(mDeviceType).append(", ");
         s.append("vendor_id: ").append(mVendorId).append(", ");
         s.append("display_name: ").append(mDisplayName);
@@ -204,6 +217,7 @@
         HdmiCecDeviceInfo other = (HdmiCecDeviceInfo) obj;
         return mLogicalAddress == other.mLogicalAddress
                 && mPhysicalAddress == other.mPhysicalAddress
+                && mPortId == other.mPortId
                 && mDeviceType == other.mDeviceType
                 && mVendorId == other.mVendorId
                 && mDisplayName.equals(other.mDisplayName);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 56fc1d6..55db1df 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -69,6 +69,86 @@
     public static final int RESULT_INCORRECT_MODE = 6;
     public static final int RESULT_COMMUNICATION_FAILED = 7;
 
+    // --- One Touch Recording success result
+    /** Recording currently selected source. Indicates the status of a recording. */
+    public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01;
+    /** Recording Digital Service. Indicates the status of a recording. */
+    public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 0x02;
+    /** Recording Analogue Service. Indicates the status of a recording. */
+    public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 0x03;
+    /** Recording External input. Indicates the status of a recording. */
+    public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 0x04;
+
+    // --- One Touch Record failure result
+    /** No recording – unable to record Digital Service. No suitable tuner. */
+    public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 0x05;
+    /** No recording – unable to record Analogue Service. No suitable tuner. */
+    public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 0x06;
+    /**
+     * No recording – unable to select required service. as suitable tuner, but the requested
+     * parameters are invalid or out of range for that tuner.
+     */
+    public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 0x07;
+    /** No recording – invalid External plug number */
+    public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 0x09;
+    /** No recording – invalid External Physical Address */
+    public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x0A;
+    /** No recording – CA system not supported */
+    public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 0x0B;
+    /** No Recording – No or Insufficient CA Entitlements” */
+    public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x0C;
+    /** No recording – Not allowed to copy source. Source is “copy never”. */
+    public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 0x0D;
+    /** No recording – No further copies allowed */
+    public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 0x0E;
+    /** No recording – No media */
+    public static final int ONE_TOUCH_RECORD_NO_MEDIA = 0x10;
+    /** No recording – playing */
+    public static final int ONE_TOUCH_RECORD_PLAYING = 0x11;
+    /** No recording – already recording */
+    public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 0x12;
+    /** No recording – media protected */
+    public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 0x13;
+    /** No recording – no source signal */
+    public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 0x14;
+    /** No recording – media problem */
+    public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 0x15;
+    /** No recording – not enough space available */
+    public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 0x16;
+    /** No recording – Parental Lock On */
+    public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 0x17;
+    /** Recording terminated normally */
+    public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 0x1A;
+    /** Recording has already terminated */
+    public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 0x1B;
+    /** No recording – other reason */
+    public static final int ONE_TOUCH_RECORD_OTHER_REASON = 0x1F;
+    // From here extra message for recording that is not mentioned in CEC spec
+    /** No recording. Previous recording request in progress. */
+    public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 0x30;
+    /** No recording. Please check recorder and connection. */
+    public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 0x31;
+    /** Cannot record currently displayed source. */
+    public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x32;
+    /** CEC is disabled. */
+    public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 0x33;
+
+    // --- Types for timer recording
+    /** Timer recording type for digital service source. */
+    public static final int TIMER_RECORDING_TYPE_DIGITAL = 1;
+    /** Timer recording type for analogue service source. */
+    public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2;
+    /** Timer recording type for external source. */
+    public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3;
+
+    // --- Extra result value for timer recording.
+    /** No timer recording - check recorder and connection. */
+    public static final int TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 0x01;
+    /** No timer recording - cannot record selected source. */
+    public static final int TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 0x02;
+    /** CEC is disabled. */
+    public static final int TIME_RECORDING_RESULT_EXTRA_CEC_DISABLED = 0x33;
+
     // True if we have a logical device of type playback hosted in the system.
     private final boolean mHasPlaybackDevice;
     // True if we have a logical device of type TV hosted in the system.
diff --git a/core/java/android/hardware/hdmi/HdmiRecordListener.java b/core/java/android/hardware/hdmi/HdmiRecordListener.java
new file mode 100644
index 0000000..0b1166b
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiRecordListener.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.annotation.SystemApi;
+import android.hardware.hdmi.HdmiRecordSources.RecordSource;
+
+/**
+ * Listener for hdmi record feature including one touch record and timer recording.
+ * @hide
+ */
+@SystemApi
+public abstract class HdmiRecordListener {
+    protected HdmiRecordListener() {}
+
+    /**
+     * Called when TV received one touch record request from record device. The client of this
+     * should use {@link HdmiRecordSources} to return it.
+     *
+     * @param recorderAddress
+     * @return record source to be used for recording. Null if no device is available.
+     */
+    public abstract RecordSource getOneTouchRecordSource(int recorderAddress);
+
+    /**
+     * Called when one touch record is started or failed during initialization.
+     *
+     * @param result result code. For more details, please look at all constants starting with
+     *            "ONE_TOUCH_RECORD_". Only
+     *            {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE},
+     *            {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE},
+     *            {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE}, and
+     *            {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT} mean normal
+     *            start of recording; otherwise, describes failure.
+     */
+    public void onOneTouchRecordResult(int result) {
+    }
+
+    /**
+     * Called when timer recording is started or failed during initialization.
+     *
+     * @param result The most significant three bytes may contain result of &lt;Timer Status&gt;
+     *        while the least significant byte may have error message like
+     *        {@link HdmiControlManager#TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION}
+     *        or
+     *        {@link HdmiControlManager #TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE}
+     *        . If the least significant byte has non zero value the most significant three bytes
+     *        may have 0 value.
+     */
+    // TODO: implement result parser.
+    public void onTimerRecordingResult(int result) {
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java
index 5a02c34..917d1d9 100644
--- a/core/java/android/hardware/hdmi/HdmiRecordSources.java
+++ b/core/java/android/hardware/hdmi/HdmiRecordSources.java
@@ -103,8 +103,10 @@
      */
     @SystemApi
     public static final class OwnSource extends RecordSource {
-        protected OwnSource() {
-            super(RECORD_SOURCE_TYPE_OWN_SOURCE, 0);
+        private static final int EXTRA_DATA_SIZE = 0;
+
+        private OwnSource() {
+            super(RECORD_SOURCE_TYPE_OWN_SOURCE, EXTRA_DATA_SIZE);
         }
 
         @Override
@@ -483,13 +485,14 @@
      * </ul>
      * @hide
      */
+    @SystemApi
     public static final class DigitalServiceSource extends RecordSource {
         /** Indicates that a service is identified by digital service IDs. */
         private static final int DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID = 0;
         /** Indicates that a service is identified by a logical or virtual channel number. */
         private static final int DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL = 1;
 
-        private static final int EXTRA_DATA_SIZE = 7;
+        static final int EXTRA_DATA_SIZE = 7;
 
         /**
          * Type of identification. It should be one of DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID and
@@ -604,8 +607,9 @@
      * </ul>
      * @hide
      */
+    @SystemApi
     public static final class AnalogueServiceSource extends RecordSource {
-        private static final int EXTRA_DATA_SIZE = 4;
+        static final int EXTRA_DATA_SIZE = 4;
 
         /** Indicates the Analogue broadcast type. */
         private final int mBroadcastType;
@@ -662,8 +666,9 @@
      * </ul>
      * @hide
      */
+    @SystemApi
     public static final class ExternalPlugData extends RecordSource {
-        private static final int EXTRA_DATA_SIZE = 1;
+        static final int EXTRA_DATA_SIZE = 1;
 
         /** External Plug number on the Recording Device. */
         private final int mPlugNumber;
@@ -706,8 +711,9 @@
      * </ul>
      * @hide
      */
+    @SystemApi
     public static final class ExternalPhysicalAddress extends RecordSource {
-        private static final int EXTRA_DATA_SIZE = 2;
+        static final int EXTRA_DATA_SIZE = 2;
 
         private final int mPhysicalAddress;
 
@@ -740,4 +746,28 @@
         byteArray[index + 1] = (byte) (value & 0xFF);
         return 2;
     }
+
+    /**
+     * Check the byte array of record source.
+     * @hide
+     */
+    @SystemApi
+    public static boolean checkRecordSource(byte[] recordSource) {
+        int recordSourceType = recordSource[0];
+        int extraDataSize = recordSource.length - 1;
+        switch (recordSourceType) {
+            case RECORD_SOURCE_TYPE_OWN_SOURCE:
+                return extraDataSize == OwnSource.EXTRA_DATA_SIZE;
+            case RECORD_SOURCE_TYPE_DIGITAL_SERVICE:
+                return extraDataSize == DigitalServiceSource.EXTRA_DATA_SIZE;
+            case RECORD_SOURCE_TYPE_ANALOGUE_SERVICE:
+                return extraDataSize == AnalogueServiceSource.EXTRA_DATA_SIZE;
+            case RECORD_SOURCE_TYPE_EXTERNAL_PLUG:
+                return extraDataSize == ExternalPlugData.EXTRA_DATA_SIZE;
+            case RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS:
+                return extraDataSize == ExternalPhysicalAddress.EXTRA_DATA_SIZE;
+            default:
+                return false;
+        }
+    }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java b/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java
index b51fa2b..01b4dd3 100644
--- a/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java
+++ b/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java
@@ -16,6 +16,10 @@
 
 package android.hardware.hdmi;
 
+import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE;
+import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
+import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
+
 import android.annotation.SystemApi;
 import android.hardware.hdmi.HdmiRecordSources.AnalogueServiceSource;
 import android.hardware.hdmi.HdmiRecordSources.DigitalServiceSource;
@@ -203,7 +207,9 @@
 
     /**
      * Place holder for time value.
+     * @hide
      */
+    @SystemApi
     public static class Time extends TimeUnit {
         private Time(int hour, int minute) {
             super(hour, minute);
@@ -212,7 +218,9 @@
 
     /**
      * Place holder for duration value.
+     * @hide
      */
+    @SystemApi
     public static class Duration extends TimeUnit {
         private Duration(int hour, int minute) {
             super(hour, minute);
@@ -287,7 +295,9 @@
      * <li>[Duration]
      * <li>[Recording Sequence]
      * </ul>
+     * @hide
      */
+    @SystemApi
     public static class TimerInfo {
         private static final int DAY_OF_MONTH_SIZE = 1;
         private static final int MONTH_OF_YEAR_SIZE = 1;
@@ -360,7 +370,9 @@
      * <li>{@link #ofExternalPlug} for external plug type
      * <li>{@link #ofExternalPhysicalAddress} for external physical address type.
      * </ul>
+     * @hide
      */
+    @SystemApi
     public static class TimerRecordSource {
         private final RecordSource mRecordSource;
         private final TimerInfo mTimerInfo;
@@ -412,4 +424,35 @@
             return getDataSize(false);
         }
     }
+
+    /**
+     * Check the byte array of timer record source.
+     * @param sourcetype
+     * @param recordSource
+     * @hide
+     */
+    @SystemApi
+    public static boolean checkTimerRecordSource(int sourcetype, byte[] recordSource) {
+        int recordSourceSize = recordSource.length - TimerInfo.BASIC_INFO_SIZE;
+        switch (sourcetype) {
+            case TIMER_RECORDING_TYPE_DIGITAL:
+                return DigitalServiceSource.EXTRA_DATA_SIZE == recordSourceSize;
+            case TIMER_RECORDING_TYPE_ANALOGUE:
+                return AnalogueServiceSource.EXTRA_DATA_SIZE == recordSourceSize;
+            case TIMER_RECORDING_TYPE_EXTERNAL:
+                int specifier = recordSource[TimerInfo.BASIC_INFO_SIZE];
+                if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG) {
+                    // One byte for specifier.
+                    return ExternalPlugData.EXTRA_DATA_SIZE + 1 == recordSourceSize;
+                } else if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS) {
+                    // One byte for specifier.
+                    return ExternalPhysicalAddress.EXTRA_DATA_SIZE + 1 == recordSourceSize;
+                } else {
+                    // Invalid specifier.
+                    return false;
+                }
+            default:
+                return false;
+        }
+    }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index c02ff8a..3436287 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -16,6 +16,8 @@
 package android.hardware.hdmi;
 
 import android.annotation.SystemApi;
+import android.hardware.hdmi.HdmiRecordSources.RecordSource;
+import android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -152,27 +154,15 @@
     }
 
     /**
-     * Callback interface to used to get notified when a record request from recorder device.
+     * Set record listener
+     *
+     * @param listener
      */
-    public interface RecordRequestListener {
-        /**
-         * Called when tv receives request request from recorder device. When it's called,
-         * it should return record source in byte array so that hdmi control service
-         * can start recording with the given source info.
-         *
-         * @return {@link HdmiRecordSources} to be used to set recording info
-         */
-        HdmiRecordSources.RecordSource onRecordRequestReceived(int recorderAddress);
-    }
-
-    /**
-     * Set {@link RecordRequestListener} to hdmi control service.
-     */
-    public void setOneTouchRecordRequestListener(RecordRequestListener listener) {
+    public void setRecordListener(HdmiRecordListener listener) {
         try {
-            mService.setOneTouchRecordRequestListener(getCallbackWrapper(listener));
+            mService.setHdmiRecordListener(getListenerWrapper(listener));
         } catch (RemoteException e) {
-            Log.e(TAG, "failed to set record request listener: ", e);
+            Log.e(TAG, "failed to set record listener.", e);
         }
     }
 
@@ -187,7 +177,7 @@
      * tvClient.startOneTouchRecord(recorderAddress, ownSource);
      * </pre>
      */
-    public void startOneTouchRecord(int recorderAddress, HdmiRecordSources.RecordSource source) {
+    public void startOneTouchRecord(int recorderAddress, RecordSource source) {
         try {
             byte[] data = new byte[source.getDataSize(true)];
             source.toByteArray(true, data, 0);
@@ -198,6 +188,19 @@
     }
 
     /**
+     * Stop one touch record.
+     *
+     * @param recorderAddress recorder address where recoding will be stopped
+     */
+    public void stopOneTouchRecord(int recorderAddress) {
+        try {
+            mService.stopOneTouchRecord(recorderAddress);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to stop record: ", e);
+        }
+    }
+
+    /**
      * Start timer recording with the given recoder address and recorder source.
      * <p>
      * Usage
@@ -211,13 +214,47 @@
      * TimerRecordSource source = HdmiTimerRecourdSources.ofDigitalSource(timerInfo, recordSource);
      * tvClient.startTimerRecording(recorderAddress, source);
      * </pre>
+     *
+     * @param recorderAddress target recorder address
+     * @param sourceType type of record source. It should be one of
+     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_DIGITAL},
+     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_ANALOGUE},
+     *          {@link HdmiControlManager#TIMER_RECORDING_TYPE_EXTERNAL}.
+     * @param source record source to be used
      */
-    public void startTimerRecording(int recorderAddress,
-            HdmiTimerRecordSources.TimerRecordSource source) {
+    public void startTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
+        checkTimerRecordingSourceType(sourceType);
+
         try {
             byte[] data = new byte[source.getDataSize()];
             source.toByteArray(data, 0);
-            mService.startTimerRecording(recorderAddress, data);
+            mService.startTimerRecording(recorderAddress, sourceType, data);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to start record: ", e);
+        }
+    }
+
+    private void checkTimerRecordingSourceType(int sourceType) {
+        switch (sourceType) {
+            case HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL:
+            case HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE:
+            case HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL:
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid source type:" + sourceType);
+        }
+    }
+
+    /**
+     * Clear timer recording with the given recorder address and recording source.
+     * For more details, please refer {@link #startTimerRecording(int, int, TimerRecordSource)}.
+     */
+    public void clearTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
+        checkTimerRecordingSourceType(sourceType);
+        try {
+            byte[] data = new byte[source.getDataSize()];
+            source.toByteArray(data, 0);
+            mService.clearTimerRecording(recorderAddress, sourceType, data);
         } catch (RemoteException e) {
             Log.e(TAG, "failed to start record: ", e);
         }
@@ -232,13 +269,12 @@
         };
     }
 
-    private static IHdmiRecordRequestListener getCallbackWrapper(
-            final RecordRequestListener listener) {
-        return new IHdmiRecordRequestListener.Stub() {
+    private static IHdmiRecordListener getListenerWrapper(final HdmiRecordListener callback) {
+        return new IHdmiRecordListener.Stub() {
             @Override
-            public byte[] onRecordRequestReceived(int recorderAddress) throws RemoteException {
+            public byte[] getOneTouchRecordSource(int recorderAddress) {
                 HdmiRecordSources.RecordSource source =
-                        listener.onRecordRequestReceived(recorderAddress);
+                        callback.getOneTouchRecordSource(recorderAddress);
                 if (source == null) {
                     return EmptyArray.BYTE;
                 }
@@ -246,6 +282,16 @@
                 source.toByteArray(true, data, 0);
                 return data;
             }
+
+            @Override
+            public void onOneTouchRecordResult(int result) {
+                callback.onOneTouchRecordResult(result);
+            }
+
+            @Override
+            public void onTimerRecordingResult(int result) {
+                callback.onTimerRecordingResult(result);
+            }
         };
     }
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 53b8b3f..808e0c9 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -22,7 +22,7 @@
 import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
 import android.hardware.hdmi.IHdmiInputChangeListener;
-import android.hardware.hdmi.IHdmiRecordRequestListener;
+import android.hardware.hdmi.IHdmiRecordListener;
 import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.hardware.hdmi.IHdmiVendorCommandListener;
 
@@ -62,7 +62,9 @@
     void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
             boolean hasVendorId);
     void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
-    void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener);
+    void setHdmiRecordListener(IHdmiRecordListener callback);
     void startOneTouchRecord(int recorderAddress, in byte[] recordSource);
-    void startTimerRecording(int recorderAddress, in byte[] recordSource);
+    void stopOneTouchRecord(int recorderAddress);
+    void startTimerRecording(int recorderAddress, int sourceType, in byte[] recordSource);
+    void clearTimerRecording(int recorderAddress, int sourceType, in byte[] recordSource);
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl b/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl
new file mode 100644
index 0000000..fba4b05
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+/**
+ * @hide
+ */
+ interface IHdmiRecordListener {
+     /**
+      * Called when TV received one touch record request from record device.
+      *
+      * @param recorderAddress
+      * @return record source in byte array.
+      */
+     byte[] getOneTouchRecordSource(int recorderAddress);
+
+     /**
+      * Called when one touch record is started or failed during initialization.
+      *
+      * @param result result code for one touch record
+      */
+     void onOneTouchRecordResult(int result);
+     /**
+      * Called when timer recording is started or failed during initialization.
+      * @param result result code for timer recording
+      */
+     void onTimerRecordingResult(int result);
+ }
\ No newline at end of file
diff --git a/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl b/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl
deleted file mode 100644
index f8f9e5f..0000000
--- a/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.hdmi;
-
-/**
- * Callback interface definition for HDMI client to fill record source info
- * when it gets record start request.
- *
- * @hide
- */
-interface IHdmiRecordRequestListener {
-    byte[] onRecordRequestReceived(int recorderAddress);
-}
\ No newline at end of file
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index 038d7ef..0bf4f25 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.soundtrigger;
 
+import android.hardware.soundtrigger.SoundTrigger;
+
 /**
  * @hide
  */
@@ -27,7 +29,7 @@
      *        TODO: See if the data being passed in works well, if not use shared memory.
      *        This *MUST* not exceed 100K.
      */
-    void onDetected(in byte[] data);
+    void onDetected(in SoundTrigger.RecognitionEvent recognitionEvent);
     /**
      * Called when the detection for the associated keyphrase stops.
      */
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index 837691a..9adc6bc 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -21,4 +21,5 @@
 parcelable SoundTrigger.KeyphraseRecognitionExtra;
 parcelable SoundTrigger.KeyphraseSoundModel;
 parcelable SoundTrigger.ModuleProperties;
-parcelable SoundTrigger.RecognitionConfig;
\ No newline at end of file
+parcelable SoundTrigger.RecognitionConfig;
+parcelable SoundTrigger.RecognitionEvent;
\ No newline at end of file
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 9a5cd9b..3e84368 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -347,12 +347,7 @@
 
         private static KeyphraseSoundModel fromParcel(Parcel in) {
             UUID uuid = UUID.fromString(in.readString());
-            byte[] data = null;
-            int dataLength = in.readInt();
-            if (dataLength >= 0) {
-                data = new byte[dataLength];
-                in.readByteArray(data);
-            }
+            byte[] data = in.readBlob();
             Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR);
             return new KeyphraseSoundModel(uuid, data, keyphrases);
         }
@@ -365,12 +360,7 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeString(uuid.toString());
-            if (data != null) {
-                dest.writeInt(data.length);
-                dest.writeByteArray(data);
-            } else {
-                dest.writeInt(-1);
-            }
+            dest.writeBlob(data);
             dest.writeTypedArray(keyphrases, 0);
         }
 
@@ -406,7 +396,7 @@
      *  {@link StatusListener#onRecognition(RecognitionEvent)}
      *  callback upon recognition success or failure.
      */
-    public static class RecognitionEvent {
+    public static class RecognitionEvent implements Parcelable {
         /** Recognition status e.g {@link #RECOGNITION_STATUS_SUCCESS} */
         public final int status;
         /** Sound Model corresponding to this event callback */
@@ -425,7 +415,7 @@
          * typically during enrollment. */
         public final byte[] data;
 
-        RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
+        public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
                 int captureSession, int captureDelayMs, int capturePreambleMs, byte[] data) {
             this.status = status;
             this.soundModelHandle = soundModelHandle;
@@ -435,6 +425,85 @@
             this.capturePreambleMs = capturePreambleMs;
             this.data = data;
         }
+
+        public static final Parcelable.Creator<RecognitionEvent> CREATOR
+                = new Parcelable.Creator<RecognitionEvent>() {
+            public RecognitionEvent createFromParcel(Parcel in) {
+                return RecognitionEvent.fromParcel(in);
+            }
+
+            public RecognitionEvent[] newArray(int size) {
+                return new RecognitionEvent[size];
+            }
+        };
+
+        private static RecognitionEvent fromParcel(Parcel in) {
+            int status = in.readInt();
+            int soundModelHandle = in.readInt();
+            boolean captureAvailable = in.readByte() == 1;
+            int captureSession = in.readInt();
+            int captureDelayMs = in.readInt();
+            int capturePreambleMs = in.readInt();
+            byte[] data = in.readBlob();
+            return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession,
+                    captureDelayMs, capturePreambleMs, data);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(status);
+            dest.writeInt(soundModelHandle);
+            dest.writeByte((byte) (captureAvailable ? 1 : 0));
+            dest.writeInt(captureSession);
+            dest.writeInt(captureDelayMs);
+            dest.writeInt(capturePreambleMs);
+            dest.writeBlob(data);
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (captureAvailable ? 1231 : 1237);
+            result = prime * result + captureDelayMs;
+            result = prime * result + capturePreambleMs;
+            result = prime * result + captureSession;
+            result = prime * result + Arrays.hashCode(data);
+            result = prime * result + soundModelHandle;
+            result = prime * result + status;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            RecognitionEvent other = (RecognitionEvent) obj;
+            if (captureAvailable != other.captureAvailable)
+                return false;
+            if (captureDelayMs != other.captureDelayMs)
+                return false;
+            if (capturePreambleMs != other.capturePreambleMs)
+                return false;
+            if (captureSession != other.captureSession)
+                return false;
+            if (!Arrays.equals(data, other.data))
+                return false;
+            if (soundModelHandle != other.soundModelHandle)
+                return false;
+            if (status != other.status)
+                return false;
+            return true;
+        }
     }
 
     /**
@@ -475,12 +544,7 @@
             boolean captureRequested = in.readByte() == 1;
             KeyphraseRecognitionExtra[] keyphrases =
                     in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
-            byte[] data = null;
-            int dataLength = in.readInt();
-            if (dataLength >= 0) {
-                data = new byte[dataLength];
-                in.readByteArray(data);
-            }
+            byte[] data = in.readBlob();
             return new RecognitionConfig(captureRequested, keyphrases, data);
         }
 
@@ -488,12 +552,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeByte((byte) (captureRequested ? 1 : 0));
             dest.writeTypedArray(keyphrases, 0);
-            if (data != null) {
-                dest.writeInt(data.length);
-                dest.writeByteArray(data);
-            } else {
-                dest.writeInt(-1);
-            }
+            dest.writeBlob(data);
         }
 
         @Override
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 13364cd..30be4da 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1084,6 +1084,65 @@
         return null;
     }
 
+    private int inferLegacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
+        if (netCap == null) {
+            return TYPE_NONE;
+        }
+        if (!netCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+            return TYPE_NONE;
+        }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
+            if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableCBS"))) {
+                return TYPE_MOBILE_CBS;
+            } else {
+                return TYPE_NONE;
+            }
+        }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+            if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableIMS"))) {
+                return TYPE_MOBILE_IMS;
+            } else {
+                return TYPE_NONE;
+            }
+        }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
+            if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableFOTA"))) {
+                return TYPE_MOBILE_FOTA;
+            } else {
+                return TYPE_NONE;
+            }
+        }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
+            if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableDUN"))) {
+                return TYPE_MOBILE_DUN;
+            } else {
+                return TYPE_NONE;
+            }
+        }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
+            if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableSUPL"))) {
+                return TYPE_MOBILE_SUPL;
+            } else {
+                return TYPE_NONE;
+            }
+        }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+            if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableMMS"))) {
+                return TYPE_MOBILE_MMS;
+            } else {
+                return TYPE_NONE;
+            }
+        }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+            if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableHIPRI"))) {
+                return TYPE_MOBILE_HIPRI;
+            } else {
+                return TYPE_NONE;
+            }
+        }
+        return TYPE_NONE;
+    }
+
     private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
         if (netCap == null) return TYPE_NONE;
         if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
@@ -1137,7 +1196,7 @@
         };
     }
 
-    private HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
+    private static HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
             new HashMap<NetworkCapabilities, LegacyRequest>();
 
     private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) {
@@ -1694,7 +1753,7 @@
 
     /**
      * Report a problem network to the framework.  This provides a hint to the system
-     * that there might be connectivity problems on this network and may cause 
+     * that there might be connectivity problems on this network and may cause
      * the framework to re-evaluate network connectivity and/or switch to another
      * network.
      *
@@ -2009,9 +2068,9 @@
 
     /** {@hide} */
     public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
-            NetworkCapabilities nc, int score) {
+            NetworkCapabilities nc, int score, NetworkMisc misc) {
         try {
-            mService.registerNetworkAgent(messenger, ni, lp, nc, score);
+            mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
         } catch (RemoteException e) { }
     }
 
@@ -2344,7 +2403,7 @@
      */
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
         sendRequestForNetwork(request.networkCapabilities, networkCallback, 0,
-                REQUEST, TYPE_NONE);
+                REQUEST, inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
     }
 
     /**
@@ -2366,7 +2425,7 @@
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
             int timeoutMs) {
         sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs,
-                REQUEST, TYPE_NONE);
+                REQUEST, inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
     }
 
     /**
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 8b12fb8..671df24 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -22,6 +22,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
+import android.net.NetworkMisc;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
@@ -64,11 +65,6 @@
     NetworkQuotaInfo getActiveNetworkQuotaInfo();
     boolean isActiveNetworkMetered();
 
-    int startUsingNetworkFeature(int networkType, in String feature,
-            in IBinder binder);
-
-    int stopUsingNetworkFeature(int networkType, in String feature);
-
     boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
 
     /** Policy control over specific {@link NetworkStateTracker}. */
@@ -150,7 +146,7 @@
     void unregisterNetworkFactory(in Messenger messenger);
 
     void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
-            in NetworkCapabilities nc, int score);
+            in NetworkCapabilities nc, int score, in NetworkMisc misc);
 
     NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
             in Messenger messenger, int timeoutSec, in IBinder binder, int legacy);
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 9a22d78..97238f1 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -23,11 +23,16 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
 import java.net.Socket;
 import java.net.SocketException;
 import java.net.UnknownHostException;
+import java.net.URL;
 import javax.net.SocketFactory;
 
+import com.android.okhttp.HostResolver;
+import com.android.okhttp.OkHttpClient;
+
 /**
  * Identifies a {@code Network}.  This is supplied to applications via
  * {@link ConnectivityManager.NetworkCallback} in response to the active
@@ -44,7 +49,11 @@
      */
     public final int netId;
 
+    // Objects used to perform per-network operations such as getSocketFactory
+    // and getBoundURL, and a lock to protect access to them.
     private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
+    private OkHttpClient mOkHttpClient = null;
+    private Object mLock = new Object();
 
     /**
      * @hide
@@ -166,12 +175,38 @@
      *         {@code Network}.
      */
     public SocketFactory getSocketFactory() {
-        if (mNetworkBoundSocketFactory == null) {
-            mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
+        synchronized (mLock) {
+            if (mNetworkBoundSocketFactory == null) {
+                mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
+            }
         }
         return mNetworkBoundSocketFactory;
     }
 
+    /**
+     * Returns a {@link URL} based on the given URL but bound to this {@code Network}.
+     * Note that if this {@code Network} ever disconnects, this factory and any URL object it
+     * produced in the past or future will cease to work.
+     *
+     * @return a {@link URL} bound to this {@code Network}.
+     */
+    public URL getBoundURL(URL url) throws MalformedURLException {
+        synchronized (mLock) {
+            if (mOkHttpClient == null) {
+                HostResolver hostResolver = new HostResolver() {
+                    @Override
+                    public InetAddress[] getAllByName(String host) throws UnknownHostException {
+                        return Network.this.getAllByName(host);
+                    }
+                };
+                mOkHttpClient = new OkHttpClient()
+                        .setSocketFactory(getSocketFactory())
+                        .setHostResolver(hostResolver);
+            }
+        }
+        return new URL(url, "", mOkHttpClient.createURLStreamHandler(url.getProtocol()));
+    }
+
     // implement the Parcelable interface
     public int describeContents() {
         return 0;
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 41eab02..22da90e 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -106,8 +106,27 @@
      */
     public static final int EVENT_UID_RANGES_REMOVED = BASE + 6;
 
+    /**
+     * Sent by the NetworkAgent to ConnectivityService to block all routes for a certain address
+     * family (AF_INET or AF_INET6) on this Network. For VPNs only.
+     * obj = Integer representing the family (AF_INET or AF_INET6)
+     */
+    public static final int EVENT_BLOCK_ADDRESS_FAMILY = BASE + 7;
+
+    /**
+     * Sent by the NetworkAgent to ConnectivityService to unblock routes for a certain address
+     * family (AF_INET or AF_INET6) on this Network. For VPNs only.
+     * obj = Integer representing the family (AF_INET or AF_INET6)
+     */
+    public static final int EVENT_UNBLOCK_ADDRESS_FAMILY = BASE + 8;
+
     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
             NetworkCapabilities nc, LinkProperties lp, int score) {
+        this(looper, context, logTag, ni, nc, lp, score, null);
+    }
+
+    public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
+            NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
         super(looper);
         LOG_TAG = logTag;
         mContext = context;
@@ -119,7 +138,7 @@
         ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
-                new LinkProperties(lp), new NetworkCapabilities(nc), score);
+                new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
     }
 
     @Override
@@ -224,6 +243,21 @@
     }
 
     /**
+     * Called by the VPN code when it wants to block an address family from being routed, typically
+     * because the VPN network doesn't support that family.
+     */
+    public void blockAddressFamily(int family) {
+        queueOrSendMessage(EVENT_BLOCK_ADDRESS_FAMILY, family);
+    }
+
+    /**
+     * Called by the VPN code when it wants to unblock an address family from being routed.
+     */
+    public void unblockAddressFamily(int family) {
+        queueOrSendMessage(EVENT_UNBLOCK_ADDRESS_FAMILY, family);
+    }
+
+    /**
      * Called when ConnectivityService has indicated they no longer want this network.
      * The parent factory should (previously) have received indication of the change
      * as well, either canceling NetworkRequests or altering their score such that this
diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/net/NetworkMisc.aidl
similarity index 82%
copy from core/java/android/service/dreams/IDozeHardware.aidl
copy to core/java/android/net/NetworkMisc.aidl
index f5a657b..c65583f 100644
--- a/core/java/android/service/dreams/IDozeHardware.aidl
+++ b/core/java/android/net/NetworkMisc.aidl
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.dreams;
+package android.net;
 
-/**
- * @hide
- */
-interface IDozeHardware {
-    byte[] sendMessage(String msg, in byte[] arg);
-}
+parcelable NetworkMisc;
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
new file mode 100644
index 0000000..34f6cf4
--- /dev/null
+++ b/core/java/android/net/NetworkMisc.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A grab-bag of information (metadata, policies, properties, etc) about a {@link Network}.
+ *
+ * @hide
+ */
+public class NetworkMisc implements Parcelable {
+    /**
+     * If the {@link Network} is a VPN, whether apps are allowed to bypass the VPN. This is set by
+     * a {@link VpnService} and used by {@link ConnectivityService} when creating a VPN.
+     */
+    public boolean allowBypass;
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(allowBypass ? 1 : 0);
+    }
+
+    public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
+        @Override
+        public NetworkMisc createFromParcel(Parcel in) {
+            NetworkMisc networkMisc = new NetworkMisc();
+            networkMisc.allowBypass = in.readInt() != 0;
+            return networkMisc;
+        }
+
+        @Override
+        public NetworkMisc[] newArray(int size) {
+            return new NetworkMisc[size];
+        }
+    };
+}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 0967fa8..9b66997 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -373,6 +373,7 @@
                 throw new IllegalArgumentException("Bad address");
             }
             mAddresses.add(new LinkAddress(address, prefixLength));
+            mConfig.updateAllowedFamilies(address);
             return this;
         }
 
@@ -413,6 +414,7 @@
                 }
             }
             mRoutes.add(new RouteInfo(new LinkAddress(address, prefixLength), null));
+            mConfig.updateAllowedFamilies(address);
             return this;
         }
 
@@ -497,7 +499,14 @@
          * @return this {@link Builder} object to facilitate chaining of method calls.
          */
         public Builder allowFamily(int family) {
-            // TODO
+            if (family == AF_INET) {
+                mConfig.allowIPv4 = true;
+            } else if (family == AF_INET6) {
+                mConfig.allowIPv6 = true;
+            } else {
+                throw new IllegalArgumentException(family + " is neither " + AF_INET + " nor " +
+                        AF_INET6);
+            }
             return this;
         }
 
@@ -563,7 +572,7 @@
          * @return this {@link Builder} object to facilitate chaining of method calls.
          */
         public Builder allowBypass() {
-            // TODO
+            mConfig.allowBypass = true;
             return this;
         }
 
@@ -577,7 +586,7 @@
          * @return this {@link Builder} object to facilitate chaining method calls.
          */
         public Builder setBlocking(boolean blocking) {
-            // TODO
+            mConfig.blocking = blocking;
             return this;
         }
 
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index c1e6664..d6ee8e0 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -367,7 +367,7 @@
     /**
      * Setup a new VPN.
      */
-    void createVirtualNetwork(int netId, boolean hasDNS);
+    void createVirtualNetwork(int netId, boolean hasDNS, boolean secure);
 
     /**
      * Remove a network.
@@ -404,4 +404,7 @@
 
     void addInterfaceToLocalNetwork(String iface, in List<RouteInfo> routes);
     void removeInterfaceFromLocalNetwork(String iface);
+
+    void blockAddressFamily(int family, int netId, String iface);
+    void unblockAddressFamily(int family, int netId, String iface);
 }
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 95cb9f3..a1c2aa1 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -246,6 +246,7 @@
     private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue);
 
     private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
+    private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len);
     private static native void nativeWriteInt(long nativePtr, int val);
     private static native void nativeWriteLong(long nativePtr, long val);
     private static native void nativeWriteFloat(long nativePtr, float val);
@@ -255,6 +256,7 @@
     private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
 
     private static native byte[] nativeCreateByteArray(long nativePtr);
+    private static native byte[] nativeReadBlob(long nativePtr);
     private static native int nativeReadInt(long nativePtr);
     private static native long nativeReadLong(long nativePtr);
     private static native float nativeReadFloat(long nativePtr);
@@ -479,6 +481,17 @@
     }
 
     /**
+     * Write a blob of data into the parcel at the current {@link #dataPosition},
+     * growing {@link #dataCapacity} if needed.
+     * @param b Bytes to place into the parcel.
+     * {@hide}
+     * {@SystemApi}
+     */
+    public final void writeBlob(byte[] b) {
+        nativeWriteBlob(mNativePtr, b, 0, (b != null) ? b.length : 0);
+    }
+
+    /**
      * Write an integer value into the parcel at the current dataPosition(),
      * growing dataCapacity() if needed.
      */
@@ -1700,6 +1713,15 @@
     }
 
     /**
+     * Read a blob of data from the parcel and return it as a byte array.
+     * {@hide}
+     * {@SystemApi}
+     */
+    public final byte[] readBlob() {
+        return nativeReadBlob(mNativePtr);
+    }
+
+    /**
      * Read and return a String[] object from the parcel.
      * {@hide}
      */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d3aee50..a506c42 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -310,6 +310,18 @@
      */
     public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
 
+    /**
+     * Key for user restrictions. Specifies if what is copied in the clipboard of this profile can
+     * be pasted in related profiles. Does not restrict if the clipboard of related profiles can be
+     * pasted in this profile.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
+
     /** @hide */
     public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
     /** @hide */
@@ -760,7 +772,7 @@
      * @return A label that combines the original label and a badge as
      *         determined by the system.
      */
-    public String getBadgedLabelForUser(String label, UserHandle user) {
+    public CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user) {
         UserInfo userInfo = getUserIfProfile(user.getIdentifier());
         if (userInfo != null && userInfo.isManagedProfile()) {
             return Resources.getSystem().getString(
@@ -770,6 +782,15 @@
     }
 
     /**
+     * Kept during L development to simplify updating unbundled apps.
+     * TODO: Remove after 2014-08-04
+     * @hide
+     */
+    public String getBadgedLabelForUser(String label, UserHandle user) {
+        return (String) getBadgedLabelForUser((CharSequence) label, user);
+    }
+
+    /**
      * If the target user is a managed profile of the calling user or the caller
      * is itself a managed profile, then this returns a drawable to use as a small
      * icon to include in a view to distinguish it from the original icon.
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index d66fc0f..671f722 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -113,7 +113,8 @@
     public boolean handleMessage(Message msg) {
         switch (msg.what) {
             case MSG_SET_STREAM_VOLUME:
-                mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+                mAudioManager.setStreamVolume(mStreamType, mLastProgress,
+                        AudioManager.FLAG_SHOW_UI_WARNINGS);
                 break;
             case MSG_START_SAMPLE:
                 onStartSample();
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 46ff58c..47cfa7d 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -116,7 +116,8 @@
 
         /**
          * Content uri used to access call log entries, including voicemail records. You must have
-         * the READ_CALL_LOG and WRITE_CALL_LOG permissions to read and write to the call log.
+         * the READ_CALL_LOG and WRITE_CALL_LOG permissions to read and write to the call log, as
+         * well as READ_VOICEMAIL and WRITE_VOICEMAIL permissions to read and write voicemails.
          */
         public static final Uri CONTENT_URI_WITH_VOICEMAIL = CONTENT_URI.buildUpon()
                 .appendQueryParameter(ALLOW_VOICEMAILS_PARAM_KEY, "true")
@@ -264,6 +265,12 @@
         public static final String VOICEMAIL_URI = "voicemail_uri";
 
         /**
+         * Transcription of the call or voicemail entry. This will only be populated for call log
+         * entries of type {@link #VOICEMAIL_TYPE} that have valid transcriptions.
+         */
+        public static final String TRANSCRIPTION = "transcription";
+
+        /**
          * Whether this item has been read or otherwise consumed by the user.
          * <p>
          * Unlike the {@link #NEW} field, which requires the user to have acknowledged the
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 829d459..03863ae 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -6802,6 +6802,21 @@
                     default: return com.android.internal.R.string.eventTypeCustom;
                 }
             }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given type,
+             * possibly substituting the given {@link #LABEL} value
+             * for {@link #TYPE_CUSTOM}.
+             */
+            public static final CharSequence getTypeLabel(Resources res, int type,
+                    CharSequence label) {
+                if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getTypeResource(type);
+                    return res.getText(labelRes);
+                }
+            }
         }
 
         /**
@@ -8018,9 +8033,8 @@
      *
      * <p>
      * By default, unpinned contacts will have a pinned position of
-     * {@link PinnedPositions#UNPINNED}, or {@link Integer#MAX_VALUE} (2^31 - 1). Client-provided
-     * pinned positions can be positive integers that range anywhere from 0 to
-     * {@link PinnedPositions#UNPINNED}.
+     * {@link PinnedPositions#UNPINNED}. Client-provided pinned positions can be positive
+     * integers that are greater than 1.
      * </p>
      */
     public static final class PinnedPositions {
@@ -8043,10 +8057,9 @@
         public static final String UNDEMOTE_METHOD = "undemote";
 
         /**
-         * Default value for the pinned position of an unpinned contact. Also equal to
-         * {@link Integer#MAX_VALUE}.
+         * Default value for the pinned position of an unpinned contact. Also equal to 0.
          */
-        public static final int UNPINNED = 0x7FFFFFFF;
+        public static final int UNPINNED = 0;
 
         /**
          * Value of pinned position for a contact that a user has indicated should be considered
@@ -8536,6 +8549,12 @@
                     "com.android.contacts.action.LIST_FREQUENT";
 
             /**
+             * The action for the "Join Contact" picker.
+             */
+            public static final String PICK_JOIN_CONTACT_ACTION =
+                    "com.android.contacts.action.JOIN_CONTACT";
+
+            /**
              * The action for the "strequent" contacts list tab. It first lists the starred
              * contacts in alphabetical order and then the frequent contacts in descending
              * order of the number of times they have been contacted.
@@ -8567,6 +8586,15 @@
              */
             public static final String FILTER_TEXT_EXTRA_KEY =
                     "com.android.contacts.extra.FILTER_TEXT";
+
+            /**
+             * Used with JOIN_CONTACT action to set the target for aggregation. This action type
+             * uses contact ids instead of contact uris for the sake of backwards compatibility.
+             * <p>
+             * Type: LONG
+             */
+            public static final String TARGET_CONTACT_ID_EXTRA_KEY
+                    = "com.android.contacts.action.CONTACT_ID";
         }
 
         /**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 325917e..d137f0c 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -256,6 +256,11 @@
      * object in the extra field. This is useful for applications that only need a small image.
      * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
      * value of EXTRA_OUTPUT.
+     * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through
+     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
+     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
+     * If you don't set a ClipData, it will be copied there for you when calling
+     * {@link Context#startActivity(Intent)}.
      * @see #EXTRA_OUTPUT
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -276,6 +281,11 @@
      * object in the extra field. This is useful for applications that only need a small image.
      * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
      * value of EXTRA_OUTPUT.
+     * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through
+     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
+     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
+     * If you don't set a ClipData, it will be copied there for you when calling
+     * {@link Context#startActivity(Intent)}.
      *
      * @see #ACTION_IMAGE_CAPTURE
      * @see #EXTRA_OUTPUT
@@ -294,6 +304,11 @@
      * where the video is written. If EXTRA_OUTPUT is not present the video will be
      * written to the standard location for videos, and the Uri of that location will be
      * returned in the data field of the Uri.
+     * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through
+     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
+     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
+     * If you don't set a ClipData, it will be copied there for you when calling
+     * {@link Context#startActivity(Intent)}.
      * @see #EXTRA_OUTPUT
      * @see #EXTRA_VIDEO_QUALITY
      * @see #EXTRA_SIZE_LIMIT
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 34d7c80..fe201cd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -131,6 +131,31 @@
             "android.settings.AIRPLANE_MODE_SETTINGS";
 
     /**
+     * Activity Action: Modify Airplane mode settings using the users voice.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+     * <p>
+     * This intent MUST be started using
+     * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity
+     * startVoiceActivity}.
+     * <p>
+     * To tell which state airplane mode should be set to, add the
+     * {@link #EXTRA_AIRPLANE_MODE_ENABLED} extra to this Intent with the state specified.
+     * If there is no extra in this Intent, no changes will be made.
+     * <p>
+     * The activity should verify that
+     * {@link android.app.Activity#isVoiceInteraction isVoiceInteraction} returns true before
+     * modifying the setting.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VOICE_CONTROL_AIRPLANE_MODE =
+            "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
+
+    /**
      * Activity Action: Show settings for accessibility modules.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -207,7 +232,6 @@
 
     /**
      * Activity Action: Show settings to allow configuration of Wi-Fi.
-
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
@@ -780,6 +804,33 @@
     public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS";
 
     /**
+     * Activity Action: Modify zen mode settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+     * <p>
+     * This intent MUST be started using
+     * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity
+     * startVoiceActivity}.
+     * <p>
+     * To tell which state zen mode should be set to, add the
+     * {@link #EXTRA_ZEN_MODE_INTERRUPTION_STATE} extra to this Intent with the state specified.
+     * If there is no extra in this Intent, no changes will be made.
+     * <p>
+     * The Activity should verify that
+     * {@link android.app.Activity#isVoiceInteraction isVoiceInteraction}.
+     * returns true before modifying the setting.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VOICE_CONTROL_ZEN_MODE =
+            "android.settings.VOICE_CONTROL_ZEN_MODE";
+
+    /**
      * Activity Action: Show the regulatory information screen for the device.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard
@@ -891,6 +942,27 @@
 
     public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
 
+    /**
+     * Activity Extra: Enable or disable Airplane Mode.
+     * <p>
+     * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_AIRPLANE_MODE}
+     * intent as a boolean.
+     */
+    public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+
+    /**
+     * Activity Extra: Modify the zen mode interruption state.
+     * <p>
+     * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_ZEN_MODE}
+     * intent as an integer. The value should be one of
+     * {@link android.provider.Settings.Global#ZEN_MODE_OFF},
+     * {@link android.provider.Settings.Global#ZEN_MODE_IMPORTANT_INTERRUPTIONS},
+     * {@link android.provider.Settings.Global#ZEN_MODE_NO_INTERRUPTIONS}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_ZEN_MODE_INTERRUPTION_STATE = "zen_mode_interruption_state";
+
     private static final String JID_RESOURCE_PREFIX = "android";
 
     public static final String AUTHORITY = "settings";
@@ -4630,6 +4702,13 @@
         public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
 
         /**
+         * Persisted playback time after a user confirmation of an unsafe volume level.
+         *
+         * @hide
+         */
+        public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -4839,6 +4918,14 @@
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global");
 
         /**
+         * Whether users are allowed to add more users or guest from lockscreen.
+         * <p>
+         * Type: int
+         * @hide
+         */
+        public static final String ADD_USERS_WHEN_LOCKED = "add_users_when_locked";
+
+        /**
          * Setting whether the global gesture for enabling accessibility is enabled.
          * If this gesture is enabled the user will be able to perfrom it to enable
          * the accessibility state without visiting the settings app.
diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java
deleted file mode 100644
index b5e7f43..0000000
--- a/core/java/android/service/dreams/DozeHardware.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.service.dreams;
-
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * Provides access to low-level hardware features that a dream may use to provide
- * a richer user experience while dozing.
- * <p>
- * This class contains functions that should be called by the dream to configure
- * hardware before starting to doze and allowing the application processor to suspend.
- * For example, the dream may provide the hardware with enough information to render
- * some content on its own without any further assistance from the application processor.
- * </p><p>
- * This object is obtained by calling {@link DreamService#getDozeHardware()}.
- * </p>
- *
- * @hide experimental
- */
-public final class DozeHardware {
-    private static final String TAG = "DozeHardware";
-
-    public static final String MSG_ENABLE_MCU = "enable_mcu";
-
-    public static final byte[] VALUE_ON = "on".getBytes();
-    public static final byte[] VALUE_OFF = "off".getBytes();
-
-    private final IDozeHardware mHardware;
-
-    DozeHardware(IDozeHardware hardware) {
-        mHardware = hardware;
-    }
-
-    /**
-     * Sets whether to enable the microcontroller.
-     *
-     * @param enable If true, enables the MCU otherwise disables it.
-     */
-    public void setEnableMcu(boolean enable) {
-        sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF);
-    }
-
-    /**
-     * Sends a message to the doze hardware module.
-     *
-     * @param msg The name of the message to send.
-     * @param arg An optional argument data blob, may be null.
-     * @return A result data blob, may be null.
-     */
-    public byte[] sendMessage(String msg, byte[] arg) {
-        if (msg == null) {
-            throw new IllegalArgumentException("msg must not be null");
-        }
-
-        try {
-            return mHardware.sendMessage(msg, arg);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to send message to doze hardware module.", ex);
-            return null;
-        }
-    }
-}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 5cf8aa6..7e04ae8 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -183,7 +183,6 @@
     private boolean mCanDoze;
     private boolean mDozing;
     private boolean mWindowless;
-    private DozeHardware mDozeHardware;
     private int mDozeScreenState = Display.STATE_UNKNOWN;
     private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
 
@@ -658,29 +657,6 @@
     }
 
     /**
-     * Gets an object that may be used to access low-level hardware features that a
-     * dream may use to provide a richer user experience while dozing.
-     *
-     * @return An instance of {@link DozeHardware} or null if this device does not offer
-     * hardware support for dozing.
-     *
-     * @hide For use by system UI components only.
-     */
-    public DozeHardware getDozeHardware() {
-        if (mCanDoze && mDozeHardware == null && mWindowToken != null) {
-            try {
-                IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
-                if (hardware != null) {
-                    mDozeHardware = new DozeHardware(hardware);
-                }
-            } catch (RemoteException ex) {
-                // system server died
-            }
-        }
-        return mDozeHardware;
-    }
-
-    /**
      * Gets the screen state to use while dozing.
      *
      * @return The screen state to use while dozing, such as {@link Display#STATE_ON},
@@ -1084,7 +1060,6 @@
         else if (canDoze()) pw.print(" candoze");
         pw.println();
         if (canDoze()) {
-            pw.println("  doze hardware: " + mDozeHardware);
             pw.println("  doze screen state: " + Display.stateToString(mDozeScreenState));
             pw.println("  doze screen brightness: " + mDozeScreenBrightness);
         }
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 648426c..be3f3b3 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -20,7 +20,6 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.IBinder;
-import android.service.dreams.IDozeHardware;
 
 /** @hide */
 interface IDreamManager {
@@ -34,5 +33,4 @@
     void finishSelf(in IBinder token, boolean immediate);
     void startDozing(in IBinder token, int screenState, int screenBrightness);
     void stopDozing(in IBinder token);
-    IDozeHardware getDozeHardware(in IBinder token);
 }
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index d685cc5..a8c08d55 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -27,6 +27,7 @@
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Message;
@@ -133,10 +134,10 @@
     private final Handler mHandler;
 
     /**
-     * The sound model for the keyphrase, derived from the model management service
-     * (IVoiceInteractionManagerService). May be null if the keyphrase isn't enrolled yet.
+     * Indicates if there is a sound model enrolled for the keyphrase,
+     * derived from the model management service (IVoiceInteractionManagerService).
      */
-    private KeyphraseSoundModel mEnrolledSoundModel;
+    private boolean mIsEnrolledForDetection;
     private int mAvailability = STATE_NOT_READY;
 
     /**
@@ -257,7 +258,7 @@
         int code = STATUS_ERROR;
         try {
             code = mModelManagementService.startRecognition(mVoiceInteractionService,
-                    mKeyphraseMetadata.id, mEnrolledSoundModel, mInternalCallback,
+                    mKeyphraseMetadata.id, mInternalCallback,
                     new RecognitionConfig(
                             captureTriggerAudio, recognitionExtra, null /* additional data */));
         } catch (RemoteException e) {
@@ -380,10 +381,10 @@
         }
 
         @Override
-        public void onDetected(byte[] data) {
+        public void onDetected(RecognitionEvent recognitionEvent) {
             Slog.i(TAG, "onDetected");
             Message message = Message.obtain(mHandler, MSG_HOTWORD_DETECTED);
-            message.obj = data;
+            message.obj = recognitionEvent.data;
             message.sendToTarget();
         }
 
@@ -417,14 +418,13 @@
         @Override
         public Void doInBackground(Void... params) {
             int availability = internalGetInitialAvailability();
-            KeyphraseSoundModel soundModel = null;
+            boolean enrolled = false;
             // Fetch the sound model if the availability is one of the supported ones.
             if (availability == STATE_NOT_READY
                     || availability == STATE_KEYPHRASE_UNENROLLED
                     || availability == STATE_KEYPHRASE_ENROLLED) {
-                soundModel =
-                        internalGetKeyphraseSoundModel(mKeyphraseMetadata.id);
-                if (soundModel == null) {
+                enrolled = internalGetIsEnrolled(mKeyphraseMetadata.id);
+                if (!enrolled) {
                     availability = STATE_KEYPHRASE_UNENROLLED;
                 } else {
                     availability = STATE_KEYPHRASE_ENROLLED;
@@ -436,8 +436,8 @@
                     Slog.d(TAG, "Hotword availability changed from " + mAvailability
                             + " -> " + availability);
                 }
+                mIsEnrolledForDetection = enrolled;
                 mAvailability = availability;
-                mEnrolledSoundModel = soundModel;
                 notifyStateChangedLocked();
             }
             return null;
@@ -475,31 +475,14 @@
         /**
          * @return The corresponding {@link KeyphraseSoundModel} or null if none is found.
          */
-        private KeyphraseSoundModel internalGetKeyphraseSoundModel(int keyphraseId) {
-            List<KeyphraseSoundModel> soundModels;
+        private boolean internalGetIsEnrolled(int keyphraseId) {
             try {
-                soundModels = mModelManagementService
-                        .listRegisteredKeyphraseSoundModels(mVoiceInteractionService);
-                if (soundModels == null || soundModels.isEmpty()) {
-                    Slog.i(TAG, "No available sound models for keyphrase ID: " + keyphraseId);
-                    return null;
-                }
-                for (int i = 0; i < soundModels.size(); i++) {
-                    KeyphraseSoundModel soundModel = soundModels.get(i);
-                    if (soundModel.keyphrases == null || soundModel.keyphrases.length == 0) {
-                        continue;
-                    }
-                    for (int j = 0; i < soundModel.keyphrases.length; j++) {
-                        Keyphrase keyphrase = soundModel.keyphrases[j];
-                        if (keyphrase.id == keyphraseId) {
-                            return soundModel;
-                        }
-                    }
-                }
+                return mModelManagementService.isEnrolledForKeyphrase(
+                        mVoiceInteractionService, keyphraseId);
             } catch (RemoteException e) {
                 Slog.w(TAG, "RemoteException in listRegisteredKeyphraseSoundModels!");
             }
-            return null;
+            return false;
         }
     }
 }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4bfcaff..a36f06c7 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -926,7 +926,7 @@
     public float getLineMax(int line) {
         float margin = getParagraphLeadingMargin(line);
         float signedExtent = getLineExtent(line, false);
-        return margin + signedExtent >= 0 ? signedExtent : -signedExtent;
+        return margin + (signedExtent >= 0 ? signedExtent : -signedExtent);
     }
 
     /**
@@ -936,7 +936,7 @@
     public float getLineWidth(int line) {
         float margin = getParagraphLeadingMargin(line);
         float signedExtent = getLineExtent(line, true);
-        return margin + signedExtent >= 0 ? signedExtent : -signedExtent;
+        return margin + (signedExtent >= 0 ? signedExtent : -signedExtent);
     }
 
     /**
@@ -1571,6 +1571,16 @@
             int len = mt.mLen;
             boolean hasTabs = false;
             TabStops tabStops = null;
+            // leading margins should be taken into account when measuring a paragraph
+            int margin = 0;
+            if (text instanceof Spanned) {
+                Spanned spanned = (Spanned) text;
+                LeadingMarginSpan[] spans = getParagraphSpans(spanned, start, end,
+                        LeadingMarginSpan.class);
+                for (LeadingMarginSpan lms : spans) {
+                    margin += lms.getLeadingMargin(true);
+                }
+            }
             for (int i = 0; i < len; ++i) {
                 if (chars[i] == '\t') {
                     hasTabs = true;
@@ -1588,7 +1598,7 @@
                 }
             }
             tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops);
-            return tl.metrics(null);
+            return margin + tl.metrics(null);
         } finally {
             TextLine.recycle(tl);
             MeasuredText.recycle(mt);
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index f34e746..aa6ad20 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -16,19 +16,38 @@
 
 package android.text.format;
 
-import android.content.res.Resources;
+import android.util.TimeFormatException;
 
+import java.io.IOException;
 import java.util.Locale;
 import java.util.TimeZone;
 
-import libcore.icu.LocaleData;
+import libcore.util.ZoneInfo;
+import libcore.util.ZoneInfoDB;
 
 /**
  * An alternative to the {@link java.util.Calendar} and
  * {@link java.util.GregorianCalendar} classes. An instance of the Time class represents
  * a moment in time, specified with second precision. It is modelled after
- * struct tm, and in fact, uses struct tm to implement most of the
- * functionality.
+ * struct tm. This class is not thread-safe and does not consider leap seconds.
+ *
+ * <p>This class has a number of issues and it is recommended that
+ * {@link java.util.GregorianCalendar} is used instead.
+ *
+ * <p>Known issues:
+ * <ul>
+ *     <li>For historical reasons when performing time calculations all arithmetic currently takes
+ *     place using 32-bit integers. This limits the reliable time range representable from 1902
+ *     until 2037.See the wikipedia article on the
+ *     <a href="http://en.wikipedia.org/wiki/Year_2038_problem">Year 2038 problem</a> for details.
+ *     Do not rely on this behavior; it may change in the future.
+ *     </li>
+ *     <li>Calling {@link #switchTimezone(String)} on a date that cannot exist, such as a wall time
+ *     that was skipped due to a DST transition, will result in a date in 1969 (i.e. -1, or 1 second
+ *     before 1st Jan 1970 UTC).</li>
+ *     <li>Much of the formatting / parsing assumes ASCII text and is therefore not suitable for
+ *     use with non-ASCII scripts.</li>
+ * </ul>
  */
 public class Time {
     private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000";
@@ -106,7 +125,7 @@
     public int isDst;
 
     /**
-     * Offset from UTC (in seconds).
+     * Offset in seconds from UTC including any DST offset.
      */
     public long gmtoff;
 
@@ -137,41 +156,20 @@
     public static final int FRIDAY = 5;
     public static final int SATURDAY = 6;
 
-    /*
-     * The Locale for which date formatting strings have been loaded.
-     */
-    private static Locale sLocale;
-    private static String[] sShortMonths;
-    private static String[] sLongMonths;
-    private static String[] sLongStandaloneMonths;
-    private static String[] sShortWeekdays;
-    private static String[] sLongWeekdays;
-    private static String sTimeOnlyFormat;
-    private static String sDateOnlyFormat;
-    private static String sDateTimeFormat;
-    private static String sAm;
-    private static String sPm;
-    private static char sZeroDigit;
-
-    // Referenced by native code.
-    private static String sDateCommand = "%a %b %e %H:%M:%S %Z %Y";
+    // An object that is reused for date calculations.
+    private TimeCalculator calculator;
 
     /**
      * Construct a Time object in the timezone named by the string
      * argument "timezone". The time is initialized to Jan 1, 1970.
-     * @param timezone string containing the timezone to use.
+     * @param timezoneId string containing the timezone to use.
      * @see TimeZone
      */
-    public Time(String timezone) {
-        if (timezone == null) {
-            throw new NullPointerException("timezone is null!");
+    public Time(String timezoneId) {
+        if (timezoneId == null) {
+            throw new NullPointerException("timezoneId is null!");
         }
-        this.timezone = timezone;
-        this.year = 1970;
-        this.monthDay = 1;
-        // Set the daylight-saving indicator to the unknown value -1 so that
-        // it will be recomputed.
-        this.isDst = -1;
+        initialize(timezoneId);
     }
 
     /**
@@ -179,7 +177,7 @@
      * Jan 1, 1970.
      */
     public Time() {
-        this(TimeZone.getDefault().getID());
+        initialize(TimeZone.getDefault().getID());
     }
 
     /**
@@ -189,9 +187,23 @@
      * @param other
      */
     public Time(Time other) {
+        initialize(other.timezone);
         set(other);
     }
 
+    /** Initialize the Time to 00:00:00 1/1/1970 in the specified timezone. */
+    private void initialize(String timezoneId) {
+        this.timezone = timezoneId;
+        this.year = 1970;
+        this.monthDay = 1;
+        // Set the daylight-saving indicator to the unknown value -1 so that
+        // it will be recomputed.
+        this.isDst = -1;
+
+        // A reusable object that performs the date/time calculations.
+        calculator = new TimeCalculator(timezoneId);
+    }
+
     /**
      * Ensures the values in each field are in range. For example if the
      * current value of this calendar is March 32, normalize() will convert it
@@ -208,14 +220,26 @@
      *
      * @return the UTC milliseconds since the epoch
      */
-    native public long normalize(boolean ignoreDst);
+    public long normalize(boolean ignoreDst) {
+        calculator.copyFieldsFromTime(this);
+        long timeInMillis = calculator.toMillis(ignoreDst);
+        calculator.copyFieldsToTime(this);
+        return timeInMillis;
+    }
 
     /**
      * Convert this time object so the time represented remains the same, but is
      * instead located in a different timezone. This method automatically calls
-     * normalize() in some cases
+     * normalize() in some cases.
+     *
+     * <p>This method can return incorrect results if the date / time cannot be normalized.
      */
-    native public void switchTimezone(String timezone);
+    public void switchTimezone(String timezone) {
+        calculator.copyFieldsFromTime(this);
+        calculator.switchTimeZone(timezone);
+        calculator.copyFieldsToTime(this);
+        this.timezone = timezone;
+    }
 
     private static final int[] DAYS_PER_MONTH = { 31, 28, 31, 30, 31, 30, 31,
             31, 30, 31, 30, 31 };
@@ -265,13 +289,13 @@
     /**
      * Clears all values, setting the timezone to the given timezone. Sets isDst
      * to a negative value to mean "unknown".
-     * @param timezone the timezone to use.
+     * @param timezoneId the timezone to use.
      */
-    public void clear(String timezone) {
-        if (timezone == null) {
+    public void clear(String timezoneId) {
+        if (timezoneId == null) {
             throw new NullPointerException("timezone is null!");
         }
-        this.timezone = timezone;
+        this.timezone = timezoneId;
         this.allDay = false;
         this.second = 0;
         this.minute = 0;
@@ -304,12 +328,12 @@
         } else if (b == null) {
             throw new NullPointerException("b == null");
         }
+        a.calculator.copyFieldsFromTime(a);
+        b.calculator.copyFieldsFromTime(b);
 
-        return nativeCompare(a, b);
+        return TimeCalculator.compare(a.calculator, b.calculator);
     }
 
-    private static native int nativeCompare(Time a, Time b);
-
     /**
      * Print the current value given the format string provided. See man
      * strftime for what means what. The final string must be less than 256
@@ -318,61 +342,21 @@
      * @return a String containing the current time expressed in the current locale.
      */
     public String format(String format) {
-        synchronized (Time.class) {
-            Locale locale = Locale.getDefault();
-
-            if (sLocale == null || locale == null || !(locale.equals(sLocale))) {
-                LocaleData localeData = LocaleData.get(locale);
-
-                sAm = localeData.amPm[0];
-                sPm = localeData.amPm[1];
-                sZeroDigit = localeData.zeroDigit;
-
-                sShortMonths = localeData.shortMonthNames;
-                sLongMonths = localeData.longMonthNames;
-                sLongStandaloneMonths = localeData.longStandAloneMonthNames;
-                sShortWeekdays = localeData.shortWeekdayNames;
-                sLongWeekdays = localeData.longWeekdayNames;
-
-                Resources r = Resources.getSystem();
-                sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day);
-                sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year);
-                sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time);
-
-                sLocale = locale;
-            }
-
-            String result = format1(format);
-            if (sZeroDigit != '0') {
-                result = localizeDigits(result);
-            }
-            return result;
-        }
+        calculator.copyFieldsFromTime(this);
+        return calculator.format(format);
     }
 
-    native private String format1(String format);
-
-    // TODO: unify this with java.util.Formatter's copy.
-    private String localizeDigits(String s) {
-        int length = s.length();
-        int offsetToLocalizedDigits = sZeroDigit - '0';
-        StringBuilder result = new StringBuilder(length);
-        for (int i = 0; i < length; ++i) {
-            char ch = s.charAt(i);
-            if (ch >= '0' && ch <= '9') {
-                ch += offsetToLocalizedDigits;
-            }
-            result.append(ch);
-        }
-        return result.toString();
-    }
-
-
     /**
      * Return the current time in YYYYMMDDTHHMMSS<tz> format
      */
     @Override
-    native public String toString();
+    public String toString() {
+        // toString() uses its own TimeCalculator rather than the shared one. Otherwise crazy stuff
+        // happens during debugging when the debugger calls toString().
+        TimeCalculator calculator = new TimeCalculator(this.timezone);
+        calculator.copyFieldsFromTime(this);
+        return calculator.toStringInternal();
+    }
 
     /**
      * Parses a date-time string in either the RFC 2445 format or an abbreviated
@@ -414,7 +398,7 @@
         if (s == null) {
             throw new NullPointerException("time string is null");
         }
-        if (nativeParse(s)) {
+        if (parseInternal(s)) {
             timezone = TIMEZONE_UTC;
             return true;
         }
@@ -424,7 +408,94 @@
     /**
      * Parse a time in the current zone in YYYYMMDDTHHMMSS format.
      */
-    native private boolean nativeParse(String s);
+    private boolean parseInternal(String s) {
+        int len = s.length();
+        if (len < 8) {
+            throw new TimeFormatException("String is too short: \"" + s +
+                    "\" Expected at least 8 characters.");
+        }
+
+        boolean inUtc = false;
+
+        // year
+        int n = getChar(s, 0, 1000);
+        n += getChar(s, 1, 100);
+        n += getChar(s, 2, 10);
+        n += getChar(s, 3, 1);
+        year = n;
+
+        // month
+        n = getChar(s, 4, 10);
+        n += getChar(s, 5, 1);
+        n--;
+        month = n;
+
+        // day of month
+        n = getChar(s, 6, 10);
+        n += getChar(s, 7, 1);
+        monthDay = n;
+
+        if (len > 8) {
+            if (len < 15) {
+                throw new TimeFormatException(
+                        "String is too short: \"" + s
+                                + "\" If there are more than 8 characters there must be at least"
+                                + " 15.");
+            }
+            checkChar(s, 8, 'T');
+            allDay = false;
+
+            // hour
+            n = getChar(s, 9, 10);
+            n += getChar(s, 10, 1);
+            hour = n;
+
+            // min
+            n = getChar(s, 11, 10);
+            n += getChar(s, 12, 1);
+            minute = n;
+
+            // sec
+            n = getChar(s, 13, 10);
+            n += getChar(s, 14, 1);
+            second = n;
+
+            if (len > 15) {
+                // Z
+                checkChar(s, 15, 'Z');
+                inUtc = true;
+            }
+        } else {
+            allDay = true;
+            hour = 0;
+            minute = 0;
+            second = 0;
+        }
+
+        weekDay = 0;
+        yearDay = 0;
+        isDst = -1;
+        gmtoff = 0;
+        return inUtc;
+    }
+
+    private void checkChar(String s, int spos, char expected) {
+        char c = s.charAt(spos);
+        if (c != expected) {
+            throw new TimeFormatException(String.format(
+                    "Unexpected character 0x%02d at pos=%d.  Expected 0x%02d (\'%c\').",
+                    (int) c, spos, (int) expected, expected));
+        }
+    }
+
+    private static int getChar(String s, int spos, int mul) {
+        char c = s.charAt(spos);
+        if (Character.isDigit(c)) {
+            return Character.getNumericValue(c) * mul;
+        } else {
+            throw new TimeFormatException("Parse error at pos=" + spos);
+        }
+    }
 
     /**
      * Parse a time in RFC 3339 format.  This method also parses simple dates
@@ -461,14 +532,140 @@
          if (s == null) {
              throw new NullPointerException("time string is null");
          }
-         if (nativeParse3339(s)) {
+         if (parse3339Internal(s)) {
              timezone = TIMEZONE_UTC;
              return true;
          }
          return false;
      }
 
-     native private boolean nativeParse3339(String s);
+     private boolean parse3339Internal(String s) {
+         int len = s.length();
+         if (len < 10) {
+             throw new TimeFormatException("String too short --- expected at least 10 characters.");
+         }
+         boolean inUtc = false;
+
+         // year
+         int n = getChar(s, 0, 1000);
+         n += getChar(s, 1, 100);
+         n += getChar(s, 2, 10);
+         n += getChar(s, 3, 1);
+         year = n;
+
+         checkChar(s, 4, '-');
+
+         // month
+         n = getChar(s, 5, 10);
+         n += getChar(s, 6, 1);
+         --n;
+         month = n;
+
+         checkChar(s, 7, '-');
+
+         // day
+         n = getChar(s, 8, 10);
+         n += getChar(s, 9, 1);
+         monthDay = n;
+
+         if (len >= 19) {
+             // T
+             checkChar(s, 10, 'T');
+             allDay = false;
+
+             // hour
+             n = getChar(s, 11, 10);
+             n += getChar(s, 12, 1);
+
+             // Note that this.hour is not set here. It is set later.
+             int hour = n;
+
+             checkChar(s, 13, ':');
+
+             // minute
+             n = getChar(s, 14, 10);
+             n += getChar(s, 15, 1);
+             // Note that this.minute is not set here. It is set later.
+             int minute = n;
+
+             checkChar(s, 16, ':');
+
+             // second
+             n = getChar(s, 17, 10);
+             n += getChar(s, 18, 1);
+             second = n;
+
+             // skip the '.XYZ' -- we don't care about subsecond precision.
+
+             int tzIndex = 19;
+             if (tzIndex < len && s.charAt(tzIndex) == '.') {
+                 do {
+                     tzIndex++;
+                 } while (tzIndex < len && Character.isDigit(s.charAt(tzIndex)));
+             }
+
+             int offset = 0;
+             if (len > tzIndex) {
+                 char c = s.charAt(tzIndex);
+                 // NOTE: the offset is meant to be subtracted to get from local time
+                 // to UTC.  we therefore use 1 for '-' and -1 for '+'.
+                 switch (c) {
+                     case 'Z':
+                         // Zulu time -- UTC
+                         offset = 0;
+                         break;
+                     case '-':
+                         offset = 1;
+                         break;
+                     case '+':
+                         offset = -1;
+                         break;
+                     default:
+                         throw new TimeFormatException(String.format(
+                                 "Unexpected character 0x%02d at position %d.  Expected + or -",
+                                 (int) c, tzIndex));
+                 }
+                 inUtc = true;
+
+                 if (offset != 0) {
+                     if (len < tzIndex + 6) {
+                         throw new TimeFormatException(
+                                 String.format("Unexpected length; should be %d characters",
+                                         tzIndex + 6));
+                     }
+
+                     // hour
+                     n = getChar(s, tzIndex + 1, 10);
+                     n += getChar(s, tzIndex + 2, 1);
+                     n *= offset;
+                     hour += n;
+
+                     // minute
+                     n = getChar(s, tzIndex + 4, 10);
+                     n += getChar(s, tzIndex + 5, 1);
+                     n *= offset;
+                     minute += n;
+                 }
+             }
+             this.hour = hour;
+             this.minute = minute;
+
+             if (offset != 0) {
+                 normalize(false);
+             }
+         } else {
+             allDay = true;
+             this.hour = 0;
+             this.minute = 0;
+             this.second = 0;
+         }
+
+         this.weekDay = 0;
+         this.yearDay = 0;
+         this.isDst = -1;
+         this.gmtoff = 0;
+         return inUtc;
+     }
 
     /**
      * Returns the timezone string that is currently set for the device.
@@ -480,7 +677,9 @@
     /**
      * Sets the time of the given Time object to the current time.
      */
-    native public void setToNow();
+    public void setToNow() {
+        set(System.currentTimeMillis());
+    }
 
     /**
      * Converts this time to milliseconds. Suitable for interacting with the
@@ -530,7 +729,10 @@
      * to read back the same milliseconds that you set with {@link #set(long)}
      * or {@link #set(Time)} or after parsing a date string.
      */
-    native public long toMillis(boolean ignoreDst);
+    public long toMillis(boolean ignoreDst) {
+        calculator.copyFieldsFromTime(this);
+        return calculator.toMillis(ignoreDst);
+    }
 
     /**
      * Sets the fields in this Time object given the UTC milliseconds.  After
@@ -539,15 +741,23 @@
      *
      * @param millis the time in UTC milliseconds since the epoch.
      */
-    native public void set(long millis);
+    public void set(long millis) {
+        allDay = false;
+        calculator.timezone = timezone;
+        calculator.setTimeInMillis(millis);
+        calculator.copyFieldsToTime(this);
+    }
 
     /**
-     * Format according to RFC 2445 DATETIME type.
+     * Format according to RFC 2445 DATE-TIME type.
      *
-     * <p>
-     * The same as format("%Y%m%dT%H%M%S").
+     * <p>The same as format("%Y%m%dT%H%M%S"), or format("%Y%m%dT%H%M%SZ") for a Time with a
+     * timezone set to "UTC".
      */
-    native public String format2445();
+    public String format2445() {
+        calculator.copyFieldsFromTime(this);
+        return calculator.format2445(!allDay);
+    }
 
     /**
      * Copy the value of that to this Time object. No normalization happens.
@@ -682,7 +892,6 @@
      * Otherwise, if the timezone is UTC, expresses the time as Y-M-D-T-H-M-S UTC</p>
      * <p>
      * Otherwise the time is expressed the time as Y-M-D-T-H-M-S +- GMT</p>
-     * @param allDay
      * @return string in the RFC 3339 format.
      */
     public String format3339(boolean allDay) {
@@ -693,7 +902,7 @@
         } else {
             String base = format(Y_M_D_T_H_M_S_000);
             String sign = (gmtoff < 0) ? "-" : "+";
-            int offset = (int)Math.abs(gmtoff);
+            int offset = (int) Math.abs(gmtoff);
             int minutes = (offset % 3600) / 60;
             int hours = offset / 3600;
 
@@ -714,16 +923,18 @@
     }
 
     /**
-     * Computes the Julian day number, given the UTC milliseconds
-     * and the offset (in seconds) from UTC.  The Julian day for a given
-     * date will be the same for every timezone.  For example, the Julian
-     * day for July 1, 2008 is 2454649.  This is the same value no matter
-     * what timezone is being used.  The Julian day is useful for testing
-     * if two events occur on the same day and for determining the relative
-     * time of an event from the present ("yesterday", "3 days ago", etc.).
+     * Computes the Julian day number for a point in time in a particular
+     * timezone. The Julian day for a given date is the same for every
+     * timezone. For example, the Julian day for July 1, 2008 is 2454649.
      *
-     * <p>
-     * Use {@link #toMillis(boolean)} to get the milliseconds.
+     * <p>Callers must pass the time in UTC millisecond (as can be returned
+     * by {@link #toMillis(boolean)} or {@link #normalize(boolean)})
+     * and the offset from UTC of the timezone in seconds (as might be in
+     * {@link #gmtoff}).
+     *
+     * <p>The Julian day is useful for testing if two events occur on the
+     * same calendar date and for determining the relative time of an event
+     * from the present ("yesterday", "3 days ago", etc.).
      *
      * @param millis the time in UTC milliseconds
      * @param gmtoff the offset from UTC in seconds
@@ -810,4 +1021,240 @@
     public static int getJulianMondayFromWeeksSinceEpoch(int week) {
         return MONDAY_BEFORE_JULIAN_EPOCH + week * 7;
     }
+
+    /**
+     * A class that handles date/time calculations.
+     *
+     * This class originated as a port of a native C++ class ("android.Time") to pure Java. It is
+     * separate from the enclosing class because some methods copy the result of calculations back
+     * to the enclosing object, but others do not: thus separate state is retained.
+     */
+    private static class TimeCalculator {
+        public final ZoneInfo.WallTime wallTime;
+        public String timezone;
+
+        // Information about the current timezone.
+        private ZoneInfo zoneInfo;
+
+        public TimeCalculator(String timezoneId) {
+            this.zoneInfo = lookupZoneInfo(timezoneId);
+            this.wallTime = new ZoneInfo.WallTime();
+        }
+
+        public long toMillis(boolean ignoreDst) {
+            if (ignoreDst) {
+                wallTime.setIsDst(-1);
+            }
+
+            int r = wallTime.mktime(zoneInfo);
+            if (r == -1) {
+                return -1;
+            }
+            return r * 1000L;
+        }
+
+        public void setTimeInMillis(long millis) {
+            // Preserve old 32-bit Android behavior.
+            int intSeconds = (int) (millis / 1000);
+
+            updateZoneInfoFromTimeZone();
+            wallTime.localtime(intSeconds, zoneInfo);
+        }
+
+        public String format(String format) {
+            if (format == null) {
+                format = "%c";
+            }
+            TimeFormatter formatter = new TimeFormatter();
+            return formatter.format(format, wallTime, zoneInfo);
+        }
+
+        private void updateZoneInfoFromTimeZone() {
+            if (!zoneInfo.getID().equals(timezone)) {
+                this.zoneInfo = lookupZoneInfo(timezone);
+            }
+        }
+
+        private static ZoneInfo lookupZoneInfo(String timezoneId) {
+            try {
+                ZoneInfo zoneInfo = ZoneInfoDB.getInstance().makeTimeZone(timezoneId);
+                if (zoneInfo == null) {
+                    zoneInfo = ZoneInfoDB.getInstance().makeTimeZone("GMT");
+                }
+                if (zoneInfo == null) {
+                    throw new AssertionError("GMT not found: \"" + timezoneId + "\"");
+                }
+                return zoneInfo;
+            } catch (IOException e) {
+                // This should not ever be thrown.
+                throw new AssertionError("Error loading timezone: \"" + timezoneId + "\"", e);
+            }
+        }
+
+        public void switchTimeZone(String timezone) {
+            int seconds = wallTime.mktime(zoneInfo);
+            this.timezone = timezone;
+            updateZoneInfoFromTimeZone();
+            wallTime.localtime(seconds, zoneInfo);
+        }
+
+        public String format2445(boolean hasTime) {
+            char[] buf = new char[hasTime ? 16 : 8];
+            int n = wallTime.getYear();
+
+            buf[0] = toChar(n / 1000);
+            n %= 1000;
+            buf[1] = toChar(n / 100);
+            n %= 100;
+            buf[2] = toChar(n / 10);
+            n %= 10;
+            buf[3] = toChar(n);
+
+            n = wallTime.getMonth() + 1;
+            buf[4] = toChar(n / 10);
+            buf[5] = toChar(n % 10);
+
+            n = wallTime.getMonthDay();
+            buf[6] = toChar(n / 10);
+            buf[7] = toChar(n % 10);
+
+            if (!hasTime) {
+                return new String(buf, 0, 8);
+            }
+
+            buf[8] = 'T';
+
+            n = wallTime.getHour();
+            buf[9] = toChar(n / 10);
+            buf[10] = toChar(n % 10);
+
+            n = wallTime.getMinute();
+            buf[11] = toChar(n / 10);
+            buf[12] = toChar(n % 10);
+
+            n = wallTime.getSecond();
+            buf[13] = toChar(n / 10);
+            buf[14] = toChar(n % 10);
+
+            if (TIMEZONE_UTC.equals(timezone)) {
+                // The letter 'Z' is appended to the end.
+                buf[15] = 'Z';
+                return new String(buf, 0, 16);
+            } else {
+                return new String(buf, 0, 15);
+            }
+        }
+
+        private char toChar(int n) {
+            return (n >= 0 && n <= 9) ? (char) (n + '0') : ' ';
+        }
+
+        /**
+         * A method that will return the state of this object in string form. Note: it has side
+         * effects and so has deliberately not been made the default {@link #toString()}.
+         */
+        public String toStringInternal() {
+            // This implementation possibly displays the un-normalized fields because that is
+            // what it has always done.
+            return String.format("%04d%02d%02dT%02d%02d%02d%s(%d,%d,%d,%d,%d)",
+                    wallTime.getYear(),
+                    wallTime.getMonth() + 1,
+                    wallTime.getMonthDay(),
+                    wallTime.getHour(),
+                    wallTime.getMinute(),
+                    wallTime.getSecond(),
+                    timezone,
+                    wallTime.getWeekDay(),
+                    wallTime.getYearDay(),
+                    wallTime.getGmtOffset(),
+                    wallTime.getIsDst(),
+                    toMillis(false /* use isDst */) / 1000
+            );
+
+        }
+
+        public static int compare(TimeCalculator aObject, TimeCalculator bObject) {
+            if (aObject.timezone.equals(bObject.timezone)) {
+                // If the timezones are the same, we can easily compare the two times.
+                int diff = aObject.wallTime.getYear() - bObject.wallTime.getYear();
+                if (diff != 0) {
+                    return diff;
+                }
+
+                diff = aObject.wallTime.getMonth() - bObject.wallTime.getMonth();
+                if (diff != 0) {
+                    return diff;
+                }
+
+                diff = aObject.wallTime.getMonthDay() - bObject.wallTime.getMonthDay();
+                if (diff != 0) {
+                    return diff;
+                }
+
+                diff = aObject.wallTime.getHour() - bObject.wallTime.getHour();
+                if (diff != 0) {
+                    return diff;
+                }
+
+                diff = aObject.wallTime.getMinute() - bObject.wallTime.getMinute();
+                if (diff != 0) {
+                    return diff;
+                }
+
+                diff = aObject.wallTime.getSecond() - bObject.wallTime.getSecond();
+                if (diff != 0) {
+                    return diff;
+                }
+
+                return 0;
+            } else {
+                // Otherwise, convert to milliseconds and compare that. This requires that object be
+                // normalized. Note: For dates that do not exist: toMillis() can return -1, which
+                // can be confused with a valid time.
+                long am = aObject.toMillis(false /* use isDst */);
+                long bm = bObject.toMillis(false /* use isDst */);
+                long diff = am - bm;
+                return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
+            }
+
+        }
+
+        public void copyFieldsToTime(Time time) {
+            time.second = wallTime.getSecond();
+            time.minute = wallTime.getMinute();
+            time.hour = wallTime.getHour();
+            time.monthDay = wallTime.getMonthDay();
+            time.month = wallTime.getMonth();
+            time.year = wallTime.getYear();
+
+            // Read-only fields that are derived from other information above.
+            time.weekDay = wallTime.getWeekDay();
+            time.yearDay = wallTime.getYearDay();
+
+            // < 0: DST status unknown, 0: is not in DST, 1: is in DST
+            time.isDst = wallTime.getIsDst();
+            // This is in seconds and includes any DST offset too.
+            time.gmtoff = wallTime.getGmtOffset();
+        }
+
+        public void copyFieldsFromTime(Time time) {
+            wallTime.setSecond(time.second);
+            wallTime.setMinute(time.minute);
+            wallTime.setHour(time.hour);
+            wallTime.setMonthDay(time.monthDay);
+            wallTime.setMonth(time.month);
+            wallTime.setYear(time.year);
+            wallTime.setWeekDay(time.weekDay);
+            wallTime.setYearDay(time.yearDay);
+            wallTime.setIsDst(time.isDst);
+            wallTime.setGmtOffset((int) time.gmtoff);
+
+            if (time.allDay && (time.second != 0 || time.minute != 0 || time.hour != 0)) {
+                throw new IllegalArgumentException("allDay is true but sec, min, hour are not 0.");
+            }
+
+            timezone = time.timezone;
+            updateZoneInfoFromTimeZone();
+        }
+    }
 }
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
new file mode 100644
index 0000000..ec79b36
--- /dev/null
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -0,0 +1,519 @@
+/*
+ * Based on the UCB version of strftime.c with the copyright notice appearing below.
+ */
+
+/*
+** Copyright (c) 1989 The Regents of the University of California.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms are permitted
+** provided that the above copyright notice and this paragraph are
+** duplicated in all such forms and that any documentation,
+** advertising materials, and other materials related to such
+** distribution and use acknowledge that the software was developed
+** by the University of California, Berkeley. The name of the
+** University may not be used to endorse or promote products derived
+** from this software without specific prior written permission.
+** THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*/
+package android.text.format;
+
+import android.content.res.Resources;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Formatter;
+import java.util.Locale;
+import java.util.TimeZone;
+import libcore.icu.LocaleData;
+import libcore.util.ZoneInfo;
+
+/**
+ * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. The
+ * main issue with this implementation is the treatment of characters as ASCII, despite returning
+ * localized (UTF-16) strings from the LocaleData.
+ *
+ * <p>This class is not thread safe.
+ */
+class TimeFormatter {
+    // An arbitrary value outside the range representable by a byte / ASCII character code.
+    private static final int FORCE_LOWER_CASE = 0x100;
+
+    private static final int SECSPERMIN = 60;
+    private static final int MINSPERHOUR = 60;
+    private static final int DAYSPERWEEK = 7;
+    private static final int MONSPERYEAR = 12;
+    private static final int HOURSPERDAY = 24;
+    private static final int DAYSPERLYEAR = 366;
+    private static final int DAYSPERNYEAR = 365;
+
+    /**
+     * The Locale for which the cached LocaleData and formats have been loaded.
+     */
+    private static Locale sLocale;
+    private static LocaleData sLocaleData;
+    private static String sTimeOnlyFormat;
+    private static String sDateOnlyFormat;
+    private static String sDateTimeFormat;
+
+    private final LocaleData localeData;
+    private final String dateTimeFormat;
+    private final String timeOnlyFormat;
+    private final String dateOnlyFormat;
+    private final Locale locale;
+
+    private StringBuilder outputBuilder;
+    private Formatter outputFormatter;
+
+    public TimeFormatter() {
+        synchronized (TimeFormatter.class) {
+            Locale locale = Locale.getDefault();
+
+            if (sLocale == null || !(locale.equals(sLocale))) {
+                sLocale = locale;
+                sLocaleData = LocaleData.get(locale);
+
+                Resources r = Resources.getSystem();
+                sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day);
+                sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year);
+                sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time);
+            }
+
+            this.dateTimeFormat = sDateTimeFormat;
+            this.timeOnlyFormat = sTimeOnlyFormat;
+            this.dateOnlyFormat = sDateOnlyFormat;
+            this.locale = locale;
+            localeData = sLocaleData;
+        }
+    }
+
+    /**
+     * Format the specified {@code wallTime} using {@code pattern}. The output is returned.
+     */
+    public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+        try {
+            StringBuilder stringBuilder = new StringBuilder();
+
+            outputBuilder = stringBuilder;
+            outputFormatter = new Formatter(stringBuilder, locale);
+
+            formatInternal(pattern, wallTime, zoneInfo);
+            String result = stringBuilder.toString();
+            // This behavior is the source of a bug since some formats are defined as being
+            // in ASCII. Generally localization is very broken.
+            if (localeData.zeroDigit != '0') {
+                result = localizeDigits(result);
+            }
+            return result;
+        } finally {
+            outputBuilder = null;
+            outputFormatter = null;
+        }
+    }
+
+    private String localizeDigits(String s) {
+        int length = s.length();
+        int offsetToLocalizedDigits = localeData.zeroDigit - '0';
+        StringBuilder result = new StringBuilder(length);
+        for (int i = 0; i < length; ++i) {
+            char ch = s.charAt(i);
+            if (ch >= '0' && ch <= '9') {
+                ch += offsetToLocalizedDigits;
+            }
+            result.append(ch);
+        }
+        return result.toString();
+    }
+
+    /**
+     * Format the specified {@code wallTime} using {@code pattern}. The output is written to
+     * {@link #outputBuilder}.
+     */
+    private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+        // Convert to ASCII bytes to be compatible with old implementation behavior.
+        byte[] bytes = pattern.getBytes(StandardCharsets.US_ASCII);
+        if (bytes.length == 0) {
+            return;
+        }
+
+        ByteBuffer formatBuffer = ByteBuffer.wrap(bytes);
+        while (formatBuffer.remaining() > 0) {
+            boolean outputCurrentByte = true;
+            char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position()));
+            if (currentByteAsChar == '%') {
+                outputCurrentByte = handleToken(formatBuffer, wallTime, zoneInfo);
+            }
+            if (outputCurrentByte) {
+                currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position()));
+                outputBuilder.append(currentByteAsChar);
+            }
+
+            formatBuffer.position(formatBuffer.position() + 1);
+        }
+    }
+
+    private boolean handleToken(ByteBuffer formatBuffer, ZoneInfo.WallTime wallTime,
+            ZoneInfo zoneInfo) {
+
+        // The byte at formatBuffer.position() is expected to be '%' at this point.
+        int modifier = 0;
+        while (formatBuffer.remaining() > 1) {
+            // Increment the position then get the new current byte.
+            formatBuffer.position(formatBuffer.position() + 1);
+            char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position()));
+            switch (currentByteAsChar) {
+                case 'A':
+                    modifyAndAppend((wallTime.getWeekDay() < 0
+                                    || wallTime.getWeekDay() >= DAYSPERWEEK)
+                                    ? "?" : localeData.longWeekdayNames[wallTime.getWeekDay() + 1],
+                            modifier);
+                    return false;
+                case 'a':
+                    modifyAndAppend((wallTime.getWeekDay() < 0
+                                    || wallTime.getWeekDay() >= DAYSPERWEEK)
+                                    ? "?" : localeData.shortWeekdayNames[wallTime.getWeekDay() + 1],
+                            modifier);
+                    return false;
+                case 'B':
+                    if (modifier == '-') {
+                        modifyAndAppend((wallTime.getMonth() < 0
+                                        || wallTime.getMonth() >= MONSPERYEAR)
+                                        ? "?"
+                                        : localeData.longStandAloneMonthNames[wallTime.getMonth()],
+                                modifier);
+                    } else {
+                        modifyAndAppend((wallTime.getMonth() < 0
+                                        || wallTime.getMonth() >= MONSPERYEAR)
+                                        ? "?" : localeData.longMonthNames[wallTime.getMonth()],
+                                modifier);
+                    }
+                    return false;
+                case 'b':
+                case 'h':
+                    modifyAndAppend((wallTime.getMonth() < 0 || wallTime.getMonth() >= MONSPERYEAR)
+                                    ? "?" : localeData.shortMonthNames[wallTime.getMonth()],
+                            modifier);
+                    return false;
+                case 'C':
+                    outputYear(wallTime.getYear(), true, false, modifier);
+                    return false;
+                case 'c':
+                    formatInternal(dateTimeFormat, wallTime, zoneInfo);
+                    return false;
+                case 'D':
+                    formatInternal("%m/%d/%y", wallTime, zoneInfo);
+                    return false;
+                case 'd':
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+                            wallTime.getMonthDay());
+                    return false;
+                case 'E':
+                case 'O':
+                    // C99 locale modifiers are not supported.
+                    continue;
+                case '_':
+                case '-':
+                case '0':
+                case '^':
+                case '#':
+                    modifier = currentByteAsChar;
+                    continue;
+                case 'e':
+                    outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
+                            wallTime.getMonthDay());
+                    return false;
+                case 'F':
+                    formatInternal("%Y-%m-%d", wallTime, zoneInfo);
+                    return false;
+                case 'H':
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+                            wallTime.getHour());
+                    return false;
+                case 'I':
+                    int hour = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12;
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour);
+                    return false;
+                case 'j':
+                    int yearDay = wallTime.getYearDay() + 1;
+                    outputFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"),
+                            yearDay);
+                    return false;
+                case 'k':
+                    outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
+                            wallTime.getHour());
+                    return false;
+                case 'l':
+                    int n2 = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12;
+                    outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2);
+                    return false;
+                case 'M':
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+                            wallTime.getMinute());
+                    return false;
+                case 'm':
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+                            wallTime.getMonth() + 1);
+                    return false;
+                case 'n':
+                    modifyAndAppend("\n", modifier);
+                    return false;
+                case 'p':
+                    modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
+                            : localeData.amPm[0], modifier);
+                    return false;
+                case 'P':
+                    modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
+                            : localeData.amPm[0], FORCE_LOWER_CASE);
+                    return false;
+                case 'R':
+                    formatInternal("%H:%M", wallTime, zoneInfo);
+                    return false;
+                case 'r':
+                    formatInternal("%I:%M:%S %p", wallTime, zoneInfo);
+                    return false;
+                case 'S':
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+                            wallTime.getSecond());
+                    return false;
+                case 's':
+                    int timeInSeconds = wallTime.mktime(zoneInfo);
+                    modifyAndAppend(Integer.toString(timeInSeconds), modifier);
+                    return false;
+                case 'T':
+                    formatInternal("%H:%M:%S", wallTime, zoneInfo);
+                    return false;
+                case 't':
+                    modifyAndAppend("\t", modifier);
+                    return false;
+                case 'U':
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+                            (wallTime.getYearDay() + DAYSPERWEEK - wallTime.getWeekDay())
+                                    / DAYSPERWEEK);
+                    return false;
+                case 'u':
+                    int day = (wallTime.getWeekDay() == 0) ? DAYSPERWEEK : wallTime.getWeekDay();
+                    outputFormatter.format("%d", day);
+                    return false;
+                case 'V':   /* ISO 8601 week number */
+                case 'G':   /* ISO 8601 year (four digits) */
+                case 'g':   /* ISO 8601 year (two digits) */
+                {
+                    int year = wallTime.getYear();
+                    int yday = wallTime.getYearDay();
+                    int wday = wallTime.getWeekDay();
+                    int w;
+                    while (true) {
+                        int len = isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR;
+                        // What yday (-3 ... 3) does the ISO year begin on?
+                        int bot = ((yday + 11 - wday) % DAYSPERWEEK) - 3;
+                        // What yday does the NEXT ISO year begin on?
+                        int top = bot - (len % DAYSPERWEEK);
+                        if (top < -3) {
+                            top += DAYSPERWEEK;
+                        }
+                        top += len;
+                        if (yday >= top) {
+                            ++year;
+                            w = 1;
+                            break;
+                        }
+                        if (yday >= bot) {
+                            w = 1 + ((yday - bot) / DAYSPERWEEK);
+                            break;
+                        }
+                        --year;
+                        yday += isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR;
+                    }
+                    if (currentByteAsChar == 'V') {
+                        outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w);
+                    } else if (currentByteAsChar == 'g') {
+                        outputYear(year, false, true, modifier);
+                    } else {
+                        outputYear(year, true, true, modifier);
+                    }
+                    return false;
+                }
+                case 'v':
+                    formatInternal("%e-%b-%Y", wallTime, zoneInfo);
+                    return false;
+                case 'W':
+                    int n = (wallTime.getYearDay() + DAYSPERWEEK - (
+                                    wallTime.getWeekDay() != 0 ? (wallTime.getWeekDay() - 1)
+                                            : (DAYSPERWEEK - 1))) / DAYSPERWEEK;
+                    outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
+                    return false;
+                case 'w':
+                    outputFormatter.format("%d", wallTime.getWeekDay());
+                    return false;
+                case 'X':
+                    formatInternal(timeOnlyFormat, wallTime, zoneInfo);
+                    return false;
+                case 'x':
+                    formatInternal(dateOnlyFormat, wallTime, zoneInfo);
+                    return false;
+                case 'y':
+                    outputYear(wallTime.getYear(), false, true, modifier);
+                    return false;
+                case 'Y':
+                    outputYear(wallTime.getYear(), true, true, modifier);
+                    return false;
+                case 'Z':
+                    if (wallTime.getIsDst() < 0) {
+                        return false;
+                    }
+                    boolean isDst = wallTime.getIsDst() != 0;
+                    modifyAndAppend(zoneInfo.getDisplayName(isDst, TimeZone.SHORT), modifier);
+                    return false;
+                case 'z': {
+                    if (wallTime.getIsDst() < 0) {
+                        return false;
+                    }
+                    int diff = wallTime.getGmtOffset();
+                    String sign;
+                    if (diff < 0) {
+                        sign = "-";
+                        diff = -diff;
+                    } else {
+                        sign = "+";
+                    }
+                    modifyAndAppend(sign, modifier);
+                    diff /= SECSPERMIN;
+                    diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR);
+                    outputFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff);
+                    return false;
+                }
+                case '+':
+                    formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfo);
+                    return false;
+                case '%':
+                    // If conversion char is undefined, behavior is undefined. Print out the
+                    // character itself.
+                default:
+                    return true;
+            }
+        }
+        return true;
+    }
+
+    private void modifyAndAppend(CharSequence str, int modifier) {
+        switch (modifier) {
+            case FORCE_LOWER_CASE:
+                for (int i = 0; i < str.length(); i++) {
+                    outputBuilder.append(brokenToLower(str.charAt(i)));
+                }
+                break;
+            case '^':
+                for (int i = 0; i < str.length(); i++) {
+                    outputBuilder.append(brokenToUpper(str.charAt(i)));
+                }
+                break;
+            case '#':
+                for (int i = 0; i < str.length(); i++) {
+                    char c = str.charAt(i);
+                    if (brokenIsUpper(c)) {
+                        c = brokenToLower(c);
+                    } else if (brokenIsLower(c)) {
+                        c = brokenToUpper(c);
+                    }
+                    outputBuilder.append(c);
+                }
+                break;
+            default:
+                outputBuilder.append(str);
+
+        }
+    }
+
+    private void outputYear(int value, boolean outputTop, boolean outputBottom, int modifier) {
+        int lead;
+        int trail;
+
+        final int DIVISOR = 100;
+        trail = value % DIVISOR;
+        lead = value / DIVISOR + trail / DIVISOR;
+        trail %= DIVISOR;
+        if (trail < 0 && lead > 0) {
+            trail += DIVISOR;
+            --lead;
+        } else if (lead < 0 && trail > 0) {
+            trail -= DIVISOR;
+            ++lead;
+        }
+        if (outputTop) {
+            if (lead == 0 && trail < 0) {
+                modifyAndAppend("-0", modifier);
+            } else {
+                outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead);
+            }
+        }
+        if (outputBottom) {
+            int n = ((trail < 0) ? -trail : trail);
+            outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
+        }
+    }
+
+    private static String getFormat(int modifier, String normal, String underscore, String dash,
+            String zero) {
+        switch (modifier) {
+            case '_':
+                return underscore;
+            case '-':
+                return dash;
+            case '0':
+                return zero;
+        }
+        return normal;
+    }
+
+    private static boolean isLeap(int year) {
+        return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
+    }
+
+    /**
+     * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII in order to
+     * be compatible with the old native implementation.
+     */
+    private static boolean brokenIsUpper(char toCheck) {
+        return toCheck >= 'A' && toCheck <= 'Z';
+    }
+
+    /**
+     * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII in order to
+     * be compatible with the old native implementation.
+     */
+    private static boolean brokenIsLower(char toCheck) {
+        return toCheck >= 'a' && toCheck <= 'z';
+    }
+
+    /**
+     * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII in order to
+     * be compatible with the old native implementation.
+     */
+    private static char brokenToLower(char input) {
+        if (input >= 'A' && input <= 'Z') {
+            return (char) (input - 'A' + 'a');
+        }
+        return input;
+    }
+
+    /**
+     * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII in order to
+     * be compatible with the old native implementation.
+     */
+    private static char brokenToUpper(char input) {
+        if (input >= 'a' && input <= 'z') {
+            return (char) (input - 'a' + 'A');
+        }
+        return input;
+    }
+
+    /**
+     * Safely convert a byte containing an ASCII character to a char, even for character codes
+     * > 127.
+     */
+    private static char convertToChar(byte b) {
+        return (char) (b & 0xFF);
+    }
+}
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index 1550297..efcbdb3 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -170,7 +170,7 @@
             int endWidth = endRight - endLeft;
             int endHeight = endBottom - endTop;
             int numChanges = 0;
-            if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
+            if ((startWidth != 0 && startHeight != 0) || (endWidth != 0 && endHeight != 0)) {
                 if (startLeft != endLeft || startTop != endTop) ++numChanges;
                 if (startRight != endRight || startBottom != endBottom) ++numChanges;
             }
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 1967213..53220d0 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1623,12 +1623,14 @@
         if (!mEnded) {
             ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
             int numOldAnims = runningAnimators.size();
-            WindowId windowId = sceneRoot.getWindowId();
-            for (int i = numOldAnims - 1; i >= 0; i--) {
-                AnimationInfo info = runningAnimators.valueAt(i);
-                if (info.view != null && windowId.equals(info.windowId)) {
-                    Animator anim = runningAnimators.keyAt(i);
-                    anim.pause();
+            if (sceneRoot != null) {
+                WindowId windowId = sceneRoot.getWindowId();
+                for (int i = numOldAnims - 1; i >= 0; i--) {
+                    AnimationInfo info = runningAnimators.valueAt(i);
+                    if (info.view != null && windowId.equals(info.windowId)) {
+                        Animator anim = runningAnimators.keyAt(i);
+                        anim.pause();
+                    }
                 }
             }
             if (mListeners != null && mListeners.size() > 0) {
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 363f97f..83c60af 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -371,6 +371,8 @@
 
     private TransitionValuesMaps removeExcludes(TransitionValuesMaps values) {
         if (mTargetIds.isEmpty() && mTargetIdExcludes == null && mTargetTypeExcludes == null
+                && mTargetNames == null && mTargetTypes == null
+                && mTargetExcludes == null && mTargetNameExcludes == null
                 && mTargets.isEmpty()) {
             return values;
         }
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index f4a0448..6820f77 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -54,9 +54,11 @@
         ArrayList<PathDataNode> list = new ArrayList<PathDataNode>();
         while (end < pathData.length()) {
             end = nextStart(pathData, end);
-            String s = pathData.substring(start, end);
-            float[] val = getFloats(s);
-            addNode(list, s.charAt(0), val);
+            String s = pathData.substring(start, end).trim();
+            if (s.length() > 0) {
+                float[] val = getFloats(s);
+                addNode(list, s.charAt(0), val);
+            }
 
             start = end;
             end++;
@@ -72,6 +74,9 @@
      * @return a deep copy of the <code>source</code>.
      */
     public static PathDataNode[] deepCopyNodes(PathDataNode[] source) {
+        if (source == null) {
+            return null;
+        }
         PathDataNode[] copy = new PathParser.PathDataNode[source.length];
         for (int i = 0; i < source.length; i ++) {
             copy[i] = new PathDataNode(source[i]);
@@ -135,6 +140,12 @@
         list.add(new PathDataNode(cmd, val));
     }
 
+    private static class ExtractFloatResult {
+        // We need to return the position of the next separator and whether the
+        // next float starts with a '-'.
+        int mEndPosition;
+        boolean mEndWithNegSign;
+    }
 
     /**
      * Parse the floats in the string.
@@ -148,42 +159,73 @@
             return new float[0];
         }
         try {
-            float[] tmp = new float[s.length()];
+            float[] results = new float[s.length()];
             int count = 0;
-            int pos = 1, end;
-            while ((end = extract(s, pos)) >= 0) {
-                if (pos < end) {
-                    tmp[count++] = Float.parseFloat(s.substring(pos, end));
+            int startPosition = 1;
+            int endPosition = 0;
+
+            ExtractFloatResult result = new ExtractFloatResult();
+            int totalLength = s.length();
+
+            // The startPosition should always be the first character of the
+            // current number, and endPosition is the character after the current
+            // number.
+            while (startPosition < totalLength) {
+                extract(s, startPosition, result);
+                endPosition = result.mEndPosition;
+
+                if (startPosition < endPosition) {
+                    results[count++] = Float.parseFloat(
+                            s.substring(startPosition, endPosition));
                 }
-                pos = end + 1;
+
+                if (result.mEndWithNegSign) {
+                    // Keep the '-' sign with next number.
+                    startPosition = endPosition;
+                } else {
+                    startPosition = endPosition + 1;
+                }
             }
-            // handle the final float if there is one
-            if (pos < s.length()) {
-                tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
-            }
-            return Arrays.copyOf(tmp, count);
-        } catch (NumberFormatException e){
-            Log.e(LOGTAG,"error in parsing \""+s+"\"");
+            return Arrays.copyOf(results, count);
+        } catch (NumberFormatException e) {
+            Log.e(LOGTAG, "error in parsing \"" + s + "\"");
             throw e;
         }
     }
 
     /**
-     * Calculate the position of the next comma or space
+     * Calculate the position of the next comma or space or negative sign
      * @param s the string to search
      * @param start the position to start searching
-     * @return the position of the next comma or space or -1 if none found
+     * @param result the result of the extraction, including the position of the
+     * the starting position of next number, whether it is ending with a '-'.
      */
-    private static int extract(String s, int start) {
-        int space = s.indexOf(' ', start);
-        int comma = s.indexOf(',', start);
-        if (space == -1) {
-            return comma;
+    private static void extract(String s, int start, ExtractFloatResult result) {
+        // Now looking for ' ', ',' or '-' from the start.
+        int currentIndex = start;
+        boolean foundSeparator = false;
+        result.mEndWithNegSign = false;
+        for (; currentIndex < s.length(); currentIndex++) {
+            char currentChar = s.charAt(currentIndex);
+            switch (currentChar) {
+                case ' ':
+                case ',':
+                    foundSeparator = true;
+                    break;
+                case '-':
+                    if (currentIndex != start) {
+                        foundSeparator = true;
+                        result.mEndWithNegSign = true;
+                    }
+                    break;
+            }
+            if (foundSeparator) {
+                break;
+            }
         }
-        if (comma == -1) {
-            return space;
-        }
-        return (comma > space) ? space : comma;
+        // When there is nothing found, then we put the end position to the end
+        // of the string.
+        result.mEndPosition = currentIndex;
     }
 
     /**
diff --git a/core/java/android/util/TimeFormatException.java b/core/java/android/util/TimeFormatException.java
index d7a898b..f520523 100644
--- a/core/java/android/util/TimeFormatException.java
+++ b/core/java/android/util/TimeFormatException.java
@@ -18,7 +18,11 @@
 
 public class TimeFormatException extends RuntimeException
 {
-    TimeFormatException(String s)
+
+    /**
+     * @hide
+     */
+    public TimeFormatException(String s)
     {
         super(s);
     }
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index b2961e5..5e49d8e 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.util.Pools.SynchronizedPool;
 
 /**
@@ -41,7 +42,6 @@
 
     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();
@@ -58,4 +58,9 @@
     long finishRecording() {
         return nFinishRecording(mRenderer);
     }
+
+    @Override
+    public boolean isRecordingFor(Object o) {
+        return o == mNode;
+    }
 }
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 73c73218..2d54acb 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -17,9 +17,11 @@
 package android.view;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Paint;
+import android.graphics.Rect;
 
 /**
  * <p>A display list records a series of graphics related operations and can replay
@@ -294,13 +296,6 @@
     // RenderProperty Setters
     ///////////////////////////////////////////////////////////////////////////
 
-    /**
-     * Set the caching property on the display list, which indicates whether the display list
-     * holds a layer. Layer display lists should avoid creating an alpha layer, since alpha is
-     * handled in the drawLayer operation directly (and more efficiently).
-     *
-     * @param caching true if the display list represents a hardware layer, false otherwise.
-     */
     public boolean setLayerType(int layerType) {
         return nSetLayerType(mNativeRenderNode, layerType);
     }
@@ -309,6 +304,14 @@
         return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0);
     }
 
+    public boolean setClipBounds(@Nullable Rect rect) {
+        if (rect == null) {
+            return nSetClipBoundsEmpty(mNativeRenderNode);
+        } else {
+            return nSetClipBounds(mNativeRenderNode, rect.left, rect.top, rect.right, rect.bottom);
+        }
+    }
+
     /**
      * Set whether the Render node should clip itself to its bounds. This property is controlled by
      * the view's parent.
@@ -594,6 +597,9 @@
      * @see #getScaleX()
      */
     public boolean setScaleX(float scaleX) {
+        if (scaleX > 1000000) {
+            throw new IllegalArgumentException("Invalid scale: " + scaleX);
+        }
         return nSetScaleX(mNativeRenderNode, scaleX);
     }
 
@@ -615,6 +621,9 @@
      * @see #getScaleY()
      */
     public boolean setScaleY(float scaleY) {
+        if (scaleY > 1000000) {
+            throw new IllegalArgumentException("Invalid scale: " + scaleY);
+        }
         return nSetScaleY(mNativeRenderNode, scaleY);
     }
 
@@ -702,85 +711,45 @@
      * @param left The left position, in pixels, of the display list
      *
      * @see View#setLeft(int)
-     * @see #getLeft()
      */
     public boolean setLeft(int left) {
         return nSetLeft(mNativeRenderNode, left);
     }
 
     /**
-     * Returns the left position for the display list in pixels.
-     *
-     * @see #setLeft(int)
-     */
-    public float getLeft() {
-        return nGetLeft(mNativeRenderNode);
-    }
-
-    /**
      * Sets the top position for the display list.
      *
      * @param top The top position, in pixels, of the display list
      *
      * @see View#setTop(int)
-     * @see #getTop()
      */
     public boolean setTop(int top) {
         return nSetTop(mNativeRenderNode, top);
     }
 
     /**
-     * Returns the top position for the display list in pixels.
-     *
-     * @see #setTop(int)
-     */
-    public float getTop() {
-        return nGetTop(mNativeRenderNode);
-    }
-
-    /**
      * Sets the right position for the display list.
      *
      * @param right The right position, in pixels, of the display list
      *
      * @see View#setRight(int)
-     * @see #getRight()
      */
     public boolean setRight(int right) {
         return nSetRight(mNativeRenderNode, right);
     }
 
     /**
-     * Returns the right position for the display list in pixels.
-     *
-     * @see #setRight(int)
-     */
-    public float getRight() {
-        return nGetRight(mNativeRenderNode);
-    }
-
-    /**
      * Sets the bottom position for the display list.
      *
      * @param bottom The bottom position, in pixels, of the display list
      *
      * @see View#setBottom(int)
-     * @see #getBottom()
      */
     public boolean setBottom(int bottom) {
         return nSetBottom(mNativeRenderNode, bottom);
     }
 
     /**
-     * Returns the bottom position for the display list in pixels.
-     *
-     * @see #setBottom(int)
-     */
-    public float getBottom() {
-        return nGetBottom(mNativeRenderNode);
-    }
-
-    /**
      * Sets the left and top positions for the display list
      *
      * @param left The left position of the display list, in pixels
@@ -805,7 +774,7 @@
      *
      * @see View#offsetLeftAndRight(int)
      */
-    public boolean offsetLeftAndRight(float offset) {
+    public boolean offsetLeftAndRight(int offset) {
         return nOffsetLeftAndRight(mNativeRenderNode, offset);
     }
 
@@ -817,7 +786,7 @@
      *
      * @see View#offsetTopAndBottom(int)
      */
-    public boolean offsetTopAndBottom(float offset) {
+    public boolean offsetTopAndBottom(int offset) {
         return nOffsetTopAndBottom(mNativeRenderNode, offset);
     }
 
@@ -860,8 +829,8 @@
 
     // Properties
 
-    private static native boolean nOffsetTopAndBottom(long renderNode, float offset);
-    private static native boolean nOffsetLeftAndRight(long renderNode, float offset);
+    private static native boolean nOffsetTopAndBottom(long renderNode, int offset);
+    private static native boolean nOffsetLeftAndRight(long renderNode, int offset);
     private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
             int right, int bottom);
     private static native boolean nSetBottom(long renderNode, int bottom);
@@ -874,6 +843,9 @@
     private static native boolean nSetLayerType(long renderNode, int layerType);
     private static native boolean nSetLayerPaint(long renderNode, long paint);
     private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
+    private static native boolean nSetClipBounds(long renderNode, int left, int top,
+            int right, int bottom);
+    private static native boolean nSetClipBoundsEmpty(long renderNode);
     private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
     private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
     private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
@@ -902,10 +874,6 @@
     private static native boolean nHasOverlappingRendering(long renderNode);
     private static native boolean nGetClipToOutline(long renderNode);
     private static native float nGetAlpha(long renderNode);
-    private static native float nGetLeft(long renderNode);
-    private static native float nGetTop(long renderNode);
-    private static native float nGetRight(long renderNode);
-    private static native float nGetBottom(long renderNode);
     private static native float nGetCameraDistance(long renderNode);
     private static native float nGetScaleX(long renderNode);
     private static native float nGetScaleY(long renderNode);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index b033780..d14f226 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -88,8 +88,8 @@
     private final float mLightY;
     private final float mLightZ;
     private final float mLightRadius;
-    private final float mAmbientShadowAlpha;
-    private final float mSpotShadowAlpha;
+    private final int mAmbientShadowAlpha;
+    private final int mSpotShadowAlpha;
 
     private long mNativeProxy;
     private boolean mInitialized = false;
@@ -104,8 +104,10 @@
         mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
         mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
         mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
-        mAmbientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
-        mSpotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
+        mAmbientShadowAlpha = Math.round(
+                255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0));
+        mSpotShadowAlpha = Math.round(
+                255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0));
         a.recycle();
 
         long rootNodePtr = nCreateRootRenderNode();
@@ -208,7 +210,9 @@
             mSurfaceHeight = height;
         }
         mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
-        nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight, lightX, mLightY, mLightZ, mLightRadius);
+        nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight,
+                lightX, mLightY, mLightZ, mLightRadius,
+                mAmbientShadowAlpha, mSpotShadowAlpha);
     }
 
     @Override
@@ -453,7 +457,8 @@
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native void nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height,
-            float lightX, float lightY, float lightZ, float lightRadius);
+            float lightX, float lightY, float lightZ, float lightRadius,
+            int ambientShadowAlpha, int spotShadowAlpha);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
     private static native int nSyncAndDrawFrame(long nativeProxy,
             long frameTimeNanos, long recordDuration, float density);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0079cc9..4c1c2f9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -724,11 +724,6 @@
     private static boolean sIgnoreMeasureCache = false;
 
     /**
-     * Ignore the clipBounds of this view for the children.
-     */
-    static boolean sIgnoreClipBoundsForChildren = false;
-
-    /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
      */
@@ -3558,9 +3553,6 @@
             // of whether a layout was requested on that View.
             sIgnoreMeasureCache = targetSdkVersion < KITKAT;
 
-            // Older apps may need this to ignore the clip bounds
-            sIgnoreClipBoundsForChildren = targetSdkVersion < L;
-
             sCompatibilityDone = true;
         }
     }
@@ -14309,6 +14301,7 @@
                 mClipBounds = null;
             }
         }
+        mRenderNode.setClipBounds(mClipBounds);
     }
 
     /**
@@ -14430,7 +14423,7 @@
      * to be called from anywhere else other than ViewGroup.drawChild().
      */
     boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
-        boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated;
+        boolean usingRenderNodeProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated;
         boolean more = false;
         final boolean childHasIdentityMatrix = hasIdentityMatrix();
         final int flags = parent.mGroupFlags;
@@ -14471,7 +14464,7 @@
                 mRenderNode.setAnimationMatrix(null);
                 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
             }
-            if (!useDisplayListProperties &&
+            if (!usingRenderNodeProperties &&
                     (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
                 final Transformation t = parent.getChildTransformation();
                 final boolean hasTransform = parent.getChildStaticTransformation(this, t);
@@ -14519,7 +14512,7 @@
             } else {
                 switch (layerType) {
                     case LAYER_TYPE_SOFTWARE:
-                        if (useDisplayListProperties) {
+                        if (usingRenderNodeProperties) {
                             hasDisplayList = canHaveDisplayList();
                         } else {
                             buildDrawingCache(true);
@@ -14527,7 +14520,7 @@
                         }
                         break;
                     case LAYER_TYPE_HARDWARE:
-                        if (useDisplayListProperties) {
+                        if (usingRenderNodeProperties) {
                             hasDisplayList = canHaveDisplayList();
                         }
                         break;
@@ -14539,8 +14532,8 @@
                 }
             }
         }
-        useDisplayListProperties &= hasDisplayList;
-        if (useDisplayListProperties) {
+        usingRenderNodeProperties &= hasDisplayList;
+        if (usingRenderNodeProperties) {
             renderNode = getDisplayList();
             if (!renderNode.isValid()) {
                 // Uncommon, but possible. If a view is removed from the hierarchy during the call
@@ -14548,7 +14541,7 @@
                 // try to use it again.
                 renderNode = null;
                 hasDisplayList = false;
-                useDisplayListProperties = false;
+                usingRenderNodeProperties = false;
             }
         }
 
@@ -14565,17 +14558,17 @@
                 layerType != LAYER_TYPE_HARDWARE;
 
         int restoreTo = -1;
-        if (!useDisplayListProperties || transformToApply != null) {
+        if (!usingRenderNodeProperties || transformToApply != null) {
             restoreTo = canvas.save();
         }
         if (offsetForScroll) {
             canvas.translate(mLeft - sx, mTop - sy);
         } else {
-            if (!useDisplayListProperties) {
+            if (!usingRenderNodeProperties) {
                 canvas.translate(mLeft, mTop);
             }
             if (scalingRequired) {
-                if (useDisplayListProperties) {
+                if (usingRenderNodeProperties) {
                     // TODO: Might not need this if we put everything inside the DL
                     restoreTo = canvas.save();
                 }
@@ -14585,7 +14578,7 @@
             }
         }
 
-        float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha());
+        float alpha = usingRenderNodeProperties ? 1 : (getAlpha() * getTransitionAlpha());
         if (transformToApply != null || alpha < 1 ||  !hasIdentityMatrix() ||
                 (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
             if (transformToApply != null || !childHasIdentityMatrix) {
@@ -14599,7 +14592,7 @@
 
                 if (transformToApply != null) {
                     if (concatMatrix) {
-                        if (useDisplayListProperties) {
+                        if (usingRenderNodeProperties) {
                             renderNode.setAnimationMatrix(transformToApply.getMatrix());
                         } else {
                             // Undo the scroll translation, apply the transformation matrix,
@@ -14618,7 +14611,7 @@
                     }
                 }
 
-                if (!childHasIdentityMatrix && !useDisplayListProperties) {
+                if (!childHasIdentityMatrix && !usingRenderNodeProperties) {
                     canvas.translate(-transX, -transY);
                     canvas.concat(getMatrix());
                     canvas.translate(transX, transY);
@@ -14642,7 +14635,7 @@
                                 layerType != LAYER_TYPE_NONE) {
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
-                        if (useDisplayListProperties) {
+                        if (usingRenderNodeProperties) {
                             renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else  if (layerType == LAYER_TYPE_NONE) {
                             final int scrollX = hasDisplayList ? 0 : sx;
@@ -14662,7 +14655,7 @@
         }
 
         if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) == ViewGroup.FLAG_CLIP_CHILDREN &&
-                !useDisplayListProperties && cache == null) {
+                !usingRenderNodeProperties && cache == null) {
             if (offsetForScroll) {
                 canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop));
             } else {
@@ -14674,7 +14667,7 @@
             }
         }
 
-        if (!useDisplayListProperties && hasDisplayList) {
+        if (!usingRenderNodeProperties && hasDisplayList) {
             renderNode = getDisplayList();
             if (!renderNode.isValid()) {
                 // Uncommon, but possible. If a view is removed from the hierarchy during the call
@@ -14687,7 +14680,7 @@
 
         if (hasNoCache) {
             boolean layerRendered = false;
-            if (layerType == LAYER_TYPE_HARDWARE && !useDisplayListProperties) {
+            if (layerType == LAYER_TYPE_HARDWARE && !usingRenderNodeProperties) {
                 final HardwareLayer layer = getHardwareLayer();
                 if (layer != null && layer.isValid()) {
                     mLayerPaint.setAlpha((int) (alpha * 255));
@@ -14774,7 +14767,8 @@
      * @param canvas The Canvas to which the View is rendered.
      */
     public void draw(Canvas canvas) {
-        if (mClipBounds != null) {
+        boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
+        if (mClipBounds != null && !usingRenderNodeProperties) {
             canvas.clipRect(mClipBounds);
         }
         final int privateFlags = mPrivateFlags;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1028a0c..27f493a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3015,6 +3015,7 @@
      */
     @Override
     protected void dispatchDraw(Canvas canvas) {
+        boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
         final int childrenCount = mChildrenCount;
         final View[] children = mChildren;
         int flags = mGroupFlags;
@@ -3059,7 +3060,7 @@
 
         int clipSaveCount = 0;
         final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
-        boolean hasClipBounds = mClipBounds != null && !sIgnoreClipBoundsForChildren;
+        boolean hasClipBounds = mClipBounds != null && !usingRenderNodeProperties;
         boolean clippingNeeded = clipToPadding || hasClipBounds;
 
         if (clippingNeeded) {
@@ -3087,7 +3088,7 @@
 
         // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
         // draw reordering internally
-        final ArrayList<View> preorderedList = canvas.isHardwareAccelerated()
+        final ArrayList<View> preorderedList = usingRenderNodeProperties
                 ? null : buildOrderedChildList();
         final boolean customOrder = preorderedList == null
                 && isChildrenDrawingOrderEnabled();
@@ -3326,7 +3327,7 @@
                     child.mRenderNode.setClipToBounds(clipChildren);
                 }
             }
-            invalidate();
+            invalidate(true);
         }
     }
 
@@ -3341,7 +3342,7 @@
     public void setClipToPadding(boolean clipToPadding) {
         if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
             setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
-            invalidate();
+            invalidate(true);
         }
     }
 
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 77d48e2..4f34231 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -40,16 +40,14 @@
 
     private final Object mLock = new Object();
 
-    private final LongArray mTempLongArray = new LongArray();
-
     private final SparseArray<AccessibilityWindowInfo> mWindowCache =
-            new SparseArray<AccessibilityWindowInfo>();
+            new SparseArray<>();
 
     private final SparseArray<LongSparseArray<AccessibilityNodeInfo>> mNodeCache =
-            new SparseArray<LongSparseArray<AccessibilityNodeInfo>>();
+            new SparseArray<>();
 
     private final SparseArray<AccessibilityWindowInfo> mTempWindowArray =
-            new SparseArray<AccessibilityWindowInfo>();
+            new SparseArray<>();
 
     public void addWindow(AccessibilityWindowInfo window) {
         synchronized (mLock) {
@@ -60,20 +58,18 @@
         }
     }
 
-    public void removeWindows(int[] windowIds) {
+    public void clearWindows() {
         synchronized (mLock) {
-            final int windowCount = windowIds.length;
-            for (int i = 0; i < windowCount; i++) {
-                final int windowId = windowIds[i];
-                AccessibilityWindowInfo window = mWindowCache.get(windowId);
+            final int windowCount = mWindowCache.size();
+            for (int i = windowCount - 1; i >= 0; i--) {
+                AccessibilityWindowInfo window = mWindowCache.valueAt(i);
                 if (window != null) {
                     if (DEBUG) {
-                        Log.i(LOG_TAG, "Removing window: " + windowId);
+                        Log.i(LOG_TAG, "Removing window: " + window.getId());
                     }
                     window.recycle();
-                    mWindowCache.remove(windowId);
+                    mWindowCache.removeAt(i);
                 }
-                clearNodesForWindowLocked(windowIds[i]);
             }
         }
     }
@@ -113,6 +109,10 @@
                 case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
                     clearSubTreeLocked(event.getWindowId(), event.getSourceNodeId());
                 } break;
+
+                case AccessibilityEvent.TYPE_WINDOWS_CHANGED: {
+                    clearWindows();
+                } break;
             }
         }
 
@@ -183,7 +183,7 @@
                     sortedWindows.put(window.getLayer(), window);
                 }
 
-                List<AccessibilityWindowInfo> windows = new ArrayList<AccessibilityWindowInfo>();
+                List<AccessibilityWindowInfo> windows = new ArrayList<>();
                 for (int i = windowCount - 1; i >= 0; i--) {
                     AccessibilityWindowInfo window = sortedWindows.valueAt(i);
                     windows.add(AccessibilityWindowInfo.obtain(window));
@@ -221,7 +221,7 @@
             final int windowId = info.getWindowId();
             LongSparseArray<AccessibilityNodeInfo> nodes = mNodeCache.get(windowId);
             if (nodes == null) {
-                nodes = new LongSparseArray<AccessibilityNodeInfo>();
+                nodes = new LongSparseArray<>();
                 mNodeCache.put(windowId, nodes);
             }
 
@@ -233,23 +233,14 @@
                 // children have been removed to remove the descendants that
                 // are no longer present.
                 final LongArray newChildrenIds = info.getChildNodeIds();
-                if (newChildrenIds != null) {
-                    // Cache the new ids as we will do some lookups.
-                    LongArray newChildNodeIds = mTempLongArray;
-                    final int newChildCount = newChildNodeIds.size();
-                    for (int i = 0; i < newChildCount; i++) {
-                        newChildNodeIds.add(newChildrenIds.get(i));
-                    }
 
-                    final int oldChildCount = oldInfo.getChildCount();
-                    for (int i = 0; i < oldChildCount; i++) {
-                        final long oldChildId = oldInfo.getChildId(i);
-                        if (newChildNodeIds.indexOf(oldChildId) < 0) {
-                            clearSubTreeLocked(windowId, oldChildId);
-                        }
+                final int oldChildCount = oldInfo.getChildCount();
+                for (int i = 0; i < oldChildCount; i++) {
+                    final long oldChildId = oldInfo.getChildId(i);
+                    // If the child is no longer present, remove the sub-tree.
+                    if (newChildrenIds == null || newChildrenIds.indexOf(oldChildId) < 0) {
+                        clearSubTreeLocked(windowId, oldChildId);
                     }
-
-                    newChildNodeIds.clear();
                 }
 
                 // Also be careful if the parent has changed since the new
@@ -397,7 +388,7 @@
                     continue;
                 }
 
-                ArraySet<AccessibilityNodeInfo> seen = new ArraySet<AccessibilityNodeInfo>();
+                ArraySet<AccessibilityNodeInfo> seen = new ArraySet<>();
                 final int windowId = mNodeCache.keyAt(i);
 
                 final int nodeCount = nodes.size();
@@ -408,6 +399,8 @@
                     if (!seen.add(node)) {
                         Log.e(LOG_TAG, "Duplicate node: " + node
                                 + " in window:" + windowId);
+                        // Stop now as we potentially found a loop.
+                        continue;
                     }
 
                     // Check for one accessibility focus.
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 4748402..db78ec5 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -84,7 +84,7 @@
     private static final Object sStaticLock = new Object();
 
     private static final LongSparseArray<AccessibilityInteractionClient> sClients =
-        new LongSparseArray<AccessibilityInteractionClient>();
+        new LongSparseArray<>();
 
     private final AtomicInteger mInteractionIdCounter = new AtomicInteger();
 
@@ -101,7 +101,7 @@
     private Message mSameThreadMessage;
 
     private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
-        new SparseArray<IAccessibilityServiceConnection>();
+        new SparseArray<>();
 
     private static final AccessibilityCache sAccessibilityCache =
         new AccessibilityCache();
@@ -163,19 +163,6 @@
     }
 
     /**
-     * Gets the root {@link AccessibilityNodeInfo} in a given window.
-     *
-     * @param connectionId The id of a connection for interacting with the system.
-     * @param windowId The window id.
-     * @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
-     */
-    public AccessibilityNodeInfo getRootInWindow(int connectionId, int windowId) {
-        return findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID, false,
-                AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
-    }
-
-    /**
      * Gets the info for a window.
      *
      * @param connectionId The id of a connection for interacting with the system.
@@ -225,11 +212,17 @@
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
-                // The system is just sending data for windows that we introspected
-                // and changed but not ones that appeared, so we have to always call
-                // into the system process. This is less expensice as opposed to
-                // sending all windows on every window change.
-                List<AccessibilityWindowInfo> windows = connection.getWindows();
+                List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows();
+                if (windows != null) {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Windows cache hit");
+                    }
+                    return windows;
+                }
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Windows cache miss");
+                }
+                windows = connection.getWindows();
                 if (windows != null) {
                     final int windowCount = windows.size();
                     for (int i = 0; i < windowCount; i++) {
@@ -534,10 +527,6 @@
         sAccessibilityCache.onAccessibilityEvent(event);
     }
 
-    public void removeWindows(int[] windowIds) {
-        sAccessibilityCache.removeWindows(windowIds);
-    }
-
     /**
      * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}.
      *
@@ -603,8 +592,7 @@
                     // instantiate new result list to avoid passing internal instances to clients.
                     final boolean isIpcCall = (Binder.getCallingPid() != Process.myPid());
                     if (!isIpcCall) {
-                        mFindAccessibilityNodeInfosResult =
-                            new ArrayList<AccessibilityNodeInfo>(infos);
+                        mFindAccessibilityNodeInfosResult = new ArrayList<>(infos);
                     } else {
                         mFindAccessibilityNodeInfosResult = infos;
                     }
@@ -795,8 +783,8 @@
             Log.e(LOG_TAG, "No root.");
         }
         // Check for duplicates.
-        HashSet<AccessibilityNodeInfo> seen = new HashSet<AccessibilityNodeInfo>();
-        Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
+        HashSet<AccessibilityNodeInfo> seen = new HashSet<>();
+        Queue<AccessibilityNodeInfo> fringe = new LinkedList<>();
         fringe.add(root);
         while (!fringe.isEmpty()) {
             AccessibilityNodeInfo current = fringe.poll();
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index e1a7ba2..7c30d2a 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -50,6 +50,12 @@
     /**
      * Sets whether the application's {@link WebView} instances should send and
      * accept cookies.
+     * By default this is set to true and the WebView accepts cookies.
+     * <p>
+     * When this is true
+     * {@link CookieManager#setAcceptThirdPartyCookies setAcceptThirdPartyCookies} and
+     * {@link CookieManager#setAcceptFileSchemeCookies setAcceptFileSchemeCookies}
+     * can be used to control the policy for those specific types of cookie.
      *
      * @param accept whether {@link WebView} instances should send and accept
      *               cookies
@@ -82,8 +88,7 @@
      * @param accept whether the {@link WebView} instance should accept
      *               third party cookies
      */
-    public synchronized void setAcceptThirdPartyCookies(WebView webview,
-            boolean accept) {
+    public void setAcceptThirdPartyCookies(WebView webview, boolean accept) {
         throw new MustOverrideException();
     }
 
@@ -292,9 +297,10 @@
     /**
      * Sets whether the application's {@link WebView} instances should send and
      * accept cookies for file scheme URLs.
-     * Use of cookies with file scheme URLs is potentially insecure. Do not use
-     * this feature unless you can be sure that no unintentional sharing of
-     * cookie data can take place.
+     * Use of cookies with file scheme URLs is potentially insecure and turned
+     * off by default.
+     * Do not use this feature unless you can be sure that no unintentional
+     * sharing of cookie data can take place.
      * <p>
      * Note that calls to this method will have no effect if made after a
      * {@link WebView} or CookieManager instance has been created.
diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
index ebfa46b..1c364c0 100644
--- a/core/java/android/webkit/CookieSyncManager.java
+++ b/core/java/android/webkit/CookieSyncManager.java
@@ -24,7 +24,7 @@
  * @deprecated The WebView now automatically syncs cookies as necessary.
  *             You no longer need to create or use the CookieSyncManager.
  *             To manually force a sync you can use the CookieManager
- *             method {@link CookieManager#flush} which is synchronous
+ *             method {@link CookieManager#flush} which is a synchronous
  *             replacement for {@link #sync}.
  *             <p>
  *
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 0a0507e..862e8c2 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -22,39 +22,41 @@
  * This interface defines a permission request and is used when web content
  * requests access to protected resources.
  *
- * Either {@link #grant(long) grant()} or {@link #deny()} must be called in UI
+ * Either {@link #grant(String[]) grant()} or {@link #deny()} must be called in UI
  * thread to respond to the request.
  */
-public interface PermissionRequest {
-    /**
-     * Resource belongs to geolocation service.
-     */
-    public final static long RESOURCE_GEOLOCATION = 1 << 0;
+public abstract class PermissionRequest {
     /**
      * Resource belongs to video capture device, like camera.
      */
-    public final static long RESOURCE_VIDEO_CAPTURE = 1 << 1;
+    public final static String RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE";
     /**
      * Resource belongs to audio capture device, like microphone.
      */
-    public final static long RESOURCE_AUDIO_CAPTURE = 1 << 2;
+    public final static String RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE";
     /**
      * Resource belongs to protected media identifier.
      * After the user grants this resource, the origin can use EME APIs to generate the license
      * requests.
      */
-    public final static long RESOURCE_PROTECTED_MEDIA_ID = 1 << 3;
+    public final static String RESOURCE_PROTECTED_MEDIA_ID =
+            "android.webkit.resource.PROTECTED_MEDIA_ID";
 
     /**
+     * Call this method to get the origin of the web page which is trying to access
+     * the restricted resources.
+     *
      * @return the origin of web content which attempt to access the restricted
      *         resources.
      */
-    public Uri getOrigin();
+    public abstract Uri getOrigin();
 
     /**
-     * @return a bit mask of resources the web content wants to access.
+     * Call this method to get the resources the web page is trying to access.
+     *
+     * @return the array of resources the web content wants to access.
      */
-    public long getResources();
+    public abstract String[] getResources();
 
     /**
      * Call this method to grant origin the permission to access the given resources.
@@ -66,10 +68,10 @@
      *        This parameter is designed to avoid granting permission by accident
      *        especially when new resources are requested by web content.
      */
-    public void grant(long resources);
+    public abstract void grant(String[] resources);
 
     /**
      * Call this method to deny the request.
      */
-    public void deny();
+    public abstract void deny();
 }
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 470d413..35c9598 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -298,7 +299,7 @@
     /**
      * Notify the host application that web content is requesting permission to
      * access the specified resources and the permission currently isn't granted
-     * or denied. The host application must invoke {@link PermissionRequest#grant(long)}
+     * or denied. The host application must invoke {@link PermissionRequest#grant(String[])}
      * or {@link PermissionRequest#deny()}.
      *
      * If this method isn't overridden, the permission is denied.
@@ -409,55 +410,93 @@
      *
      * @see FileChooserParams
      */
-    public boolean showFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
+    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
             FileChooserParams fileChooserParams) {
         return false;
     }
 
     /**
-     * Parameters used in the {@link #showFileChooser} method.
-     * This is intended to be used as a read-only data struct by the application.
+     * UploadHelper simplifies file upload operations by providing helper methods that
+     * would handle most common file picker/media capture requests. The application
+     * can use the helper to build an intent to start a file picker, and then parse
+     * the result returned by the activity.
+     *
+     * How to use:
+     * 1. Create a helper using {@link FileChooserParams#getUploadHelper}
+     * 2. Build an intent using {@link UploadHelper#buildIntent}
+     * 3. Fire the intent using {@link android.app.Activity#startActivityForResult}.
+     * 4. Check for ActivityNotFoundException and take a user friendly action if thrown.
+     * 5. Listen the result using {@link android.app.Activity#onActivityResult}
+     * 6. Parse the result using {@link UploadHelper#parseResult}
+     * 7. Send the result using filePathCallback of {@link WebChromeClient#onShowFileChooser}
      */
-    public static class FileChooserParams {
-        // Flags for mode
-        /** Bitflag for <code>mode</code> indicating multiple files maybe selected */
-        public static final int MODE_OPEN_MULTIPLE = 1 << 0;
-        /** Bitflag for <code>mode</code> indicating a folder  maybe selected.
-         * The implementation should enumerate all files selected by this operation */
-        public static final int MODE_OPEN_FOLDER = 1 << 1;
-        /** Bitflag for <code>mode</code> indicating a non-existant filename maybe returned */
-        public static final int MODE_SAVE = 1 << 2;
+    public static abstract class UploadHelper {
+        /**
+         * Returns an intent that would start a file picker for file selection/media capture.
+         */
+        public abstract Intent buildIntent();
 
         /**
-         * Bit-field of the <code>MODE_</code> flags.
+         * Parses the result returned by the file picker activity.
          *
-         * 0 indicates plain single file open.
+         * @param resultCode the integer result code returned by the file picker activity.
+         * @param data the intent returned by the file picker activity.
+         * @return the Uris of selected file(s) or null if the resultCode indicates
+         *         activity canceled or any other error.
          */
-        public int mode;
+        public abstract Uri[] parseResult(int resultCode, Intent data);
+    }
+
+    /**
+     * Parameters used in the {@link #onShowFileChooser} method.
+     */
+    public static abstract class FileChooserParams {
+        /** Open single file. Requires that the file exists before allowing the user to pick it. */
+        public static final int OPEN = 0;
+        /** Like Open but allows multiple files to be selected. */
+        public static final int OPEN_MULTIPLE = 1;
+        /** Like Open but allows a folder to be selected. The implementation should enumerate
+            all files selected by this operation. */
+        public static final int OPEN_FOLDER = 2;
+        /**  Allows picking a nonexistent file and saving it. */
+        public static final int SAVE = 3;
 
         /**
-         * Comma-seperated list of acceptable MIME types.
+         * Returns a helper to simplify choosing and uploading files. The helper builds a default
+         * intent that the application can send using startActivityForResult and processes the
+         * results.
          */
-        public String acceptTypes;
+        public abstract UploadHelper getUploadHelper();
 
         /**
-         * true indicates a preference for a live media captured value (e.g. Camera, Microphone).
+         * Returns file chooser mode.
+         */
+        public abstract int getMode();
+
+        /**
+         * Returns an array of acceptable MIME types. The array will be empty if no
+         * acceptable types are specified.
+         */
+        public abstract String[] getAcceptTypes();
+
+        /**
+         * Returns preference for a live media captured value (e.g. Camera, Microphone).
+         * True indicates capture is enabled, false disabled.
          *
-         * Use <code>acceptTypes</code> to determine suitable capture devices.
+         * Use <code>getAcceptTypes</code> to determine suitable capture devices.
          */
-        public boolean capture;
+        public abstract boolean isCaptureEnabled();
 
         /**
-         * The title to use for this file selector, or null.
-         *
-         * Maybe null, in which case a default title should be used.
+         * Returns the title to use for this file selector, or null. If null a default
+         * title should be used.
          */
-        public String title;
+        public abstract CharSequence getTitle();
 
         /**
-         * Name of a default selection if appropriate, or null.
+         * The file path of a default selection if specified, or null.
          */
-        public String defaultFilename;
+        public abstract String getDefaultFilename();
     };
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9cf3e4f..e07a6e3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -88,7 +88,7 @@
  * </pre>
  * <p>See {@link android.content.Intent} for more information.</p>
  *
- * <p>To provide a WebView in your own Activity, include a {@code <WebView>} in your layout,
+ * <p>To provide a WebView in your own Activity, include a {@code &lt;WebView&gt;} in your layout,
  * or set the entire Activity window as a WebView during {@link
  * android.app.Activity#onCreate(Bundle) onCreate()}:</p>
  * <pre class="prettyprint">
@@ -1624,6 +1624,16 @@
     }
 
     /**
+     * Enable drawing the entire HTML document at a significant performance
+     * cost. Call this to enable drawing and capturing HTML content outside of
+     * the WebView's viewport. This should be called before any WebViews are
+     * created.
+     */
+    public static void enableSlowWholeDocumentDraw() {
+        getFactory().getStatics().enableSlowWholeDocumentDraw();
+    }
+
+    /**
      * Clears the highlighting surrounding text matches created by
      * {@link #findAllAsync}.
      */
@@ -1681,23 +1691,6 @@
     }
 
     /**
-     * Preauthorize the given origin to access resources.
-     * The authorization only valid for this WebView instance's life cycle and
-     * will not retained.
-     *
-     * In the case that an origin has had resources preauthorized, calls to
-     * {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will not be
-     * made for those resources from that origin.
-     *
-     * @param origin the origin authorized to access resources
-     * @param resources the resource authorized to be accessed by origin.
-     */
-    public void preauthorizePermission(Uri origin, long resources) {
-        checkThread();
-        mProvider.preauthorizePermission(origin, resources);
-    }
-
-    /**
      * Sets the Picture listener. This is an interface used to receive
      * notifications of a new Picture.
      *
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 5ff2655..48f3ca3 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -64,6 +64,12 @@
          * {@link android.webkit.WebView#optOutDataReductionProxy() }
          */
         void optOutDataReductionProxy();
+
+        /**
+         * Implements the API method:
+         * {@link android.webkit.WebView#setSlowWholeDocumentDrawEnabled(boolean) }
+         */
+        void enableSlowWholeDocumentDraw();
     }
 
     Statics getStatics();
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 13cd2bd..fe18138 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -248,8 +248,6 @@
 
     public View findHierarchyView(String className, int hashCode);
 
-    public void preauthorizePermission(Uri origin, long resources);
-
     //-------------------------------------------------------------------------
     // Provider internal methods
     //-------------------------------------------------------------------------
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index be7e0bc..2708525 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.animation.ObjectAnimator;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -63,6 +64,9 @@
      * progress.
      */
     private int mKeyProgressIncrement = 1;
+    private ObjectAnimator mPositionAnimator;
+    private static final int PROGRESS_ANIMATION_DURATION = 250;
+
 
     private static final int NO_ALPHA = 0xFF;
     private float mDisabledAlpha;
@@ -361,18 +365,17 @@
     void onProgressRefresh(float scale, boolean fromUser) {
         super.onProgressRefresh(scale, fromUser);
 
-        final Drawable thumb = mThumb;
-        if (thumb != null) {
-            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
-
-            // Since we draw translated, the drawable's bounds that it signals
-            // for invalidation won't be the actual bounds we want invalidated,
-            // so just invalidate this whole view.
-            invalidate();
+        if (!isAnimationRunning()) {
+            setThumbPos(scale);
         }
     }
 
     @Override
+    void onAnimatePosition(float scale, boolean fromUser) {
+        setThumbPos(scale);
+    }
+
+    @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
 
@@ -414,6 +417,18 @@
         return max > 0 ? getProgress() / (float) max : 0;
     }
 
+    private void setThumbPos(float scale) {
+        final Drawable thumb = mThumb;
+        if (thumb != null) {
+            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
+            // Since we draw translated, the drawable's bounds that it signals
+            // for invalidation won't be the actual bounds we want invalidated,
+            // so just invalidate this whole view.
+            invalidate();
+
+        }
+    }
+
     /**
      * Updates the thumb drawable bounds.
      *
@@ -676,13 +691,13 @@
             switch (keyCode) {
                 case KeyEvent.KEYCODE_DPAD_LEFT:
                     if (progress <= 0) break;
-                    setProgress(progress - mKeyProgressIncrement, true);
+                    animateSetProgress(progress - mKeyProgressIncrement);
                     onKeyChange();
                     return true;
 
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
                     if (progress >= getMax()) break;
-                    setProgress(progress + mKeyProgressIncrement, true);
+                    animateSetProgress(progress + mKeyProgressIncrement);
                     onKeyChange();
                     return true;
             }
@@ -691,6 +706,38 @@
         return super.onKeyDown(keyCode, event);
     }
 
+    boolean isAnimationRunning() {
+        return mPositionAnimator != null && mPositionAnimator.isRunning();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setProgress(int progress, boolean fromUser) {
+        if (isAnimationRunning()) {
+            mPositionAnimator.cancel();
+        }
+        super.setProgress(progress, fromUser);
+    }
+
+    void animateSetProgress(int progress) {
+        float curProgress = isAnimationRunning() ? getAnimationPosition() : getProgress();
+
+        if (progress < 0) {
+            progress = 0;
+        } else if (progress > getMax()) {
+            progress = getMax();
+        }
+        setProgressValueOnly(progress);
+
+        mPositionAnimator = ObjectAnimator.ofFloat(this, "animationPosition", curProgress,
+                progress);
+        mPositionAnimator.setDuration(PROGRESS_ANIMATION_DURATION);
+        mPositionAnimator.setAutoCancel(true);
+        mPositionAnimator.start();
+    }
+
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 84b213b..af4644b 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1186,15 +1186,27 @@
         /** Timeout before disallowing intercept on the source's parent. */
         private final int mTapTimeout;
 
+        /** Timeout before accepting a long-press to start forwarding. */
+        private final int mLongPressTimeout;
+
         /** Source view from which events are forwarded. */
         private final View mSrc;
 
         /** Runnable used to prevent conflicts with scrolling parents. */
         private Runnable mDisallowIntercept;
 
+        /** Runnable used to trigger forwarding on long-press. */
+        private Runnable mTriggerLongPress;
+
         /** Whether this listener is currently forwarding touch events. */
         private boolean mForwarding;
 
+        /**
+         * Whether forwarding was initiated by a long-press. If so, we won't
+         * force the window to dismiss when the touch stream ends.
+         */
+        private boolean mWasLongPress;
+
         /** The id of the first pointer down in the current event stream. */
         private int mActivePointerId;
 
@@ -1203,6 +1215,9 @@
             mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
             mTapTimeout = ViewConfiguration.getTapTimeout();
 
+            // Use a medium-press timeout. Halfway between tap and long-press.
+            mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
+
             src.addOnAttachStateChangeListener(this);
         }
 
@@ -1223,7 +1238,14 @@
             final boolean wasForwarding = mForwarding;
             final boolean forwarding;
             if (wasForwarding) {
-                forwarding = onTouchForwarded(event) || !onForwardingStopped();
+                if (mWasLongPress) {
+                    // If we started forwarding as a result of a long-press,
+                    // just silently stop forwarding events so that the window
+                    // stays open.
+                    forwarding = onTouchForwarded(event);
+                } else {
+                    forwarding = onTouchForwarded(event) || !onForwardingStopped();
+                }
             } else {
                 forwarding = onTouchObserved(event) && onForwardingStarted();
 
@@ -1305,21 +1327,29 @@
             switch (actionMasked) {
                 case MotionEvent.ACTION_DOWN:
                     mActivePointerId = srcEvent.getPointerId(0);
+                    mWasLongPress = false;
+
                     if (mDisallowIntercept == null) {
                         mDisallowIntercept = new DisallowIntercept();
                     }
                     src.postDelayed(mDisallowIntercept, mTapTimeout);
+
+                    if (mTriggerLongPress == null) {
+                        mTriggerLongPress = new TriggerLongPress();
+                    }
+                    src.postDelayed(mTriggerLongPress, mLongPressTimeout);
                     break;
                 case MotionEvent.ACTION_MOVE:
                     final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
                     if (activePointerIndex >= 0) {
                         final float x = srcEvent.getX(activePointerIndex);
                         final float y = srcEvent.getY(activePointerIndex);
+
+                        // Has the pointer has moved outside of the view?
                         if (!src.pointInView(x, y, mScaledTouchSlop)) {
-                            // The pointer has moved outside of the view.
-                            if (mDisallowIntercept != null) {
-                                src.removeCallbacks(mDisallowIntercept);
-                            }
+                            clearCallbacks();
+
+                            // Don't let the parent intercept our events.
                             src.getParent().requestDisallowInterceptTouchEvent(true);
                             return true;
                         }
@@ -1327,15 +1357,48 @@
                     break;
                 case MotionEvent.ACTION_CANCEL:
                 case MotionEvent.ACTION_UP:
-                    if (mDisallowIntercept != null) {
-                        src.removeCallbacks(mDisallowIntercept);
-                    }
+                    clearCallbacks();
                     break;
             }
 
             return false;
         }
 
+        private void clearCallbacks() {
+            if (mTriggerLongPress != null) {
+                mSrc.removeCallbacks(mTriggerLongPress);
+            }
+
+            if (mDisallowIntercept != null) {
+                mSrc.removeCallbacks(mDisallowIntercept);
+            }
+        }
+
+        private void onLongPress() {
+            clearCallbacks();
+
+            final View src = mSrc;
+            if (!src.isEnabled()) {
+                return;
+            }
+
+            if (!onForwardingStarted()) {
+                return;
+            }
+
+            // Don't let the parent intercept our events.
+            mSrc.getParent().requestDisallowInterceptTouchEvent(true);
+
+            // Make sure we cancel any ongoing source event stream.
+            final long now = SystemClock.uptimeMillis();
+            final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
+            mSrc.onTouchEvent(e);
+            e.recycle();
+
+            mForwarding = true;
+            mWasLongPress = true;
+        }
+
         /**
          * Handled forwarded motion events and determines when to stop
          * forwarding.
@@ -1379,6 +1442,13 @@
                 parent.requestDisallowInterceptTouchEvent(true);
             }
         }
+
+        private class TriggerLongPress implements Runnable {
+            @Override
+            public void run() {
+                onLongPress();
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 20c1aa4..4a30809 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -242,6 +242,8 @@
     private long mUiThreadId;
     private boolean mShouldStartAnimationDrawable;
 
+    private float mAnimationPosition;
+
     private boolean mInDrawing;
     private boolean mAttached;
     private boolean mRefreshIsPosted;
@@ -259,7 +261,7 @@
     public ProgressBar(Context context) {
         this(context, null);
     }
-    
+
     public ProgressBar(Context context, AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.progressBarStyle);
     }
@@ -276,9 +278,9 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
-        
+
         mNoInvalidate = true;
-        
+
         final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
         if (progressDrawable != null) {
             // Calling this method can set mMaxHeight, make sure the corresponding
@@ -297,11 +299,11 @@
         mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
 
         final int resID = a.getResourceId(
-                com.android.internal.R.styleable.ProgressBar_interpolator, 
+                com.android.internal.R.styleable.ProgressBar_interpolator,
                 android.R.anim.linear_interpolator); // default to linear interpolator
         if (resID > 0) {
             setInterpolator(context, resID);
-        } 
+        }
 
         setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
 
@@ -386,12 +388,12 @@
      * traverse layer and state list drawables.
      */
     private Drawable tileify(Drawable drawable, boolean clip) {
-        
+
         if (drawable instanceof LayerDrawable) {
             LayerDrawable background = (LayerDrawable) drawable;
             final int N = background.getNumberOfLayers();
             Drawable[] outDrawables = new Drawable[N];
-            
+
             for (int i = 0; i < N; i++) {
                 int id = background.getId(i);
                 outDrawables[i] = tileify(background.getDrawable(i),
@@ -399,13 +401,13 @@
             }
 
             LayerDrawable newBg = new LayerDrawable(outDrawables);
-            
+
             for (int i = 0; i < N; i++) {
                 newBg.setId(i, background.getId(i));
             }
-            
+
             return newBg;
-            
+
         } else if (drawable instanceof StateListDrawable) {
             StateListDrawable in = (StateListDrawable) drawable;
             StateListDrawable out = new StateListDrawable();
@@ -414,7 +416,7 @@
                 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
             }
             return out;
-            
+
         } else if (drawable instanceof BitmapDrawable) {
             final BitmapDrawable bitmap = (BitmapDrawable) drawable;
             final Bitmap tileBitmap = bitmap.getBitmap();
@@ -434,7 +436,7 @@
             return clip ? new ClipDrawable(
                     shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL) : shapeDrawable;
         }
-        
+
         return drawable;
     }
 
@@ -442,7 +444,7 @@
         final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
         return new RoundRectShape(roundedCorners, null, null);
     }
-    
+
     /**
      * Convert a AnimationDrawable for use as a barberpole animation.
      * Each frame of the animation is wrapped in a ClipDrawable and
@@ -454,7 +456,7 @@
             final int N = background.getNumberOfFrames();
             AnimationDrawable newBg = new AnimationDrawable();
             newBg.setOneShot(background.isOneShot());
-            
+
             for (int i = 0; i < N; i++) {
                 Drawable frame = tileify(background.getFrame(i), true);
                 frame.setLevel(10000);
@@ -465,7 +467,7 @@
         }
         return drawable;
     }
-    
+
     /**
      * <p>
      * Initialize the progress bar's default values:
@@ -506,7 +508,7 @@
      * <p>Change the indeterminate mode for this progress bar. In indeterminate
      * mode, the progress is ignored and the progress bar shows an infinite
      * animation instead.</p>
-     * 
+     *
      * If this progress bar's style only supports indeterminate mode (such as the circular
      * progress bars), then this will be ignored.
      *
@@ -657,7 +659,7 @@
 
         setIndeterminateDrawable(d);
     }
-    
+
     /**
      * <p>Get the drawable used to draw the progress bar in
      * progress mode.</p>
@@ -963,7 +965,7 @@
 
         setProgressDrawable(d);
     }
-    
+
     /**
      * @return The drawable currently used to draw the progress bar
      */
@@ -1014,7 +1016,7 @@
                 final int count = mRefreshData.size();
                 for (int i = 0; i < count; i++) {
                     final RefreshData rd = mRefreshData.get(i);
-                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
+                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
                     rd.recycle();
                 }
                 mRefreshData.clear();
@@ -1029,10 +1031,12 @@
                 new SynchronizedPool<RefreshData>(POOL_MAX);
 
         public int id;
-        public int progress;
+        public float progress;
         public boolean fromUser;
+        public boolean animate;
 
-        public static RefreshData obtain(int id, int progress, boolean fromUser) {
+        public static RefreshData obtain(int id, float progress, boolean fromUser,
+                boolean animate) {
             RefreshData rd = sPool.acquire();
             if (rd == null) {
                 rd = new RefreshData();
@@ -1040,9 +1044,10 @@
             rd.id = id;
             rd.progress = progress;
             rd.fromUser = fromUser;
+            rd.animate = animate;
             return rd;
         }
-        
+
         public void recycle() {
             sPool.release(this);
         }
@@ -1064,9 +1069,19 @@
         layer.mutate().setTint(tint, tintMode);
     }
 
-    private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
+    private float getScale(float progress) {
+        return mMax > 0 ? progress / (float) mMax : 0;
+    }
+
+    private synchronized void doRefreshProgress(int id, float progress, boolean fromUser,
             boolean callBackToApp) {
-        float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
+        doRefreshProgress(id, progress, fromUser, callBackToApp, false);
+    }
+
+    private synchronized void doRefreshProgress(int id, float progress, boolean fromUser,
+            boolean callBackToApp, boolean animate) {
+        float scale = getScale(progress);
+
         final Drawable d = mCurrentDrawable;
         if (d != null) {
             Drawable progressDrawable = null;
@@ -1083,27 +1098,65 @@
         } else {
             invalidate();
         }
-        
-        if (callBackToApp && id == R.id.progress) {
-            onProgressRefresh(scale, fromUser);
+
+        if (id == R.id.progress) {
+            if (animate) {
+                onAnimatePosition(scale, fromUser);
+            } else if (callBackToApp) {
+                onProgressRefresh(scale, fromUser);
+            }
         }
     }
 
+    /**
+     * Called when a ProgressBar is animating its position.
+     *
+     * @param scale Current position/progress between 0 and 1.
+     * @param fromUser True if the progress change was initiated by the user.
+     */
+    void onAnimatePosition(float scale, boolean fromUser) {
+    }
+
+    /**
+     * Sets the progress value without going through the entire refresh process.
+     *
+     * @see #setProgress(int, boolean)
+     * @param progress The new progress, between 0 and {@link #getMax()}
+     */
+    void setProgressValueOnly(int progress) {
+        mProgress = progress;
+        onProgressRefresh(getScale(progress), true);
+    }
+
+    void setAnimationPosition(float position) {
+        mAnimationPosition = position;
+        refreshProgress(R.id.progress, position, true, true);
+    }
+
+    float getAnimationPosition() {
+        return mAnimationPosition;
+    }
+
     void onProgressRefresh(float scale, boolean fromUser) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
             scheduleAccessibilityEventSender();
         }
     }
 
-    private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
+    private synchronized void refreshProgress(int id, float progress, boolean fromUser) {
+        refreshProgress(id, progress, fromUser, false);
+    }
+
+    private synchronized void refreshProgress(int id, float progress, boolean fromUser,
+            boolean animate) {
         if (mUiThreadId == Thread.currentThread().getId()) {
-            doRefreshProgress(id, progress, fromUser, true);
+            doRefreshProgress(id, progress, fromUser, true, animate);
         } else {
             if (mRefreshProgressRunnable == null) {
                 mRefreshProgressRunnable = new RefreshProgressRunnable();
             }
 
-            final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
+            final RefreshData rd = RefreshData.obtain(id, progress, fromUser, animate);
             mRefreshData.add(rd);
             if (mAttached && !mRefreshIsPosted) {
                 post(mRefreshProgressRunnable);
@@ -1111,7 +1164,7 @@
             }
         }
     }
-    
+
     /**
      * <p>Set the current progress to the specified value. Does not do anything
      * if the progress bar is in indeterminate mode.</p>
@@ -1121,13 +1174,13 @@
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
      * @see #getProgress()
-     * @see #incrementProgressBy(int) 
+     * @see #incrementProgressBy(int)
      */
     @android.view.RemotableViewMethod
     public synchronized void setProgress(int progress) {
         setProgress(progress, false);
     }
-    
+
     @android.view.RemotableViewMethod
     synchronized void setProgress(int progress, boolean fromUser) {
         if (mIndeterminate) {
@@ -1153,7 +1206,7 @@
      * Set the current secondary progress to the specified value. Does not do
      * anything if the progress bar is in indeterminate mode.
      * </p>
-     * 
+     *
      * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
@@ -1234,8 +1287,8 @@
      * @param max the upper range of this progress bar
      *
      * @see #getMax()
-     * @see #setProgress(int) 
-     * @see #setSecondaryProgress(int) 
+     * @see #setProgress(int)
+     * @see #setSecondaryProgress(int)
      */
     @android.view.RemotableViewMethod
     public synchronized void setMax(int max) {
@@ -1252,13 +1305,13 @@
             refreshProgress(R.id.progress, mProgress, false);
         }
     }
-    
+
     /**
      * <p>Increase the progress bar's progress by the specified amount.</p>
      *
      * @param diff the amount by which the progress must be increased
      *
-     * @see #setProgress(int) 
+     * @see #setProgress(int)
      */
     public synchronized final void incrementProgressBy(int diff) {
         setProgress(mProgress + diff);
@@ -1269,7 +1322,7 @@
      *
      * @param diff the amount by which the secondary progress must be increased
      *
-     * @see #setSecondaryProgress(int) 
+     * @see #setSecondaryProgress(int)
      */
     public synchronized final void incrementSecondaryProgressBy(int diff) {
         setSecondaryProgress(mSecondaryProgress + diff);
@@ -1292,13 +1345,13 @@
             if (mInterpolator == null) {
                 mInterpolator = new LinearInterpolator();
             }
-    
+
             if (mTransformation == null) {
                 mTransformation = new Transformation();
             } else {
                 mTransformation.clear();
             }
-            
+
             if (mAnimation == null) {
                 mAnimation = new AlphaAnimation(0.0f, 1.0f);
             } else {
@@ -1449,7 +1502,7 @@
             }
             mIndeterminateDrawable.setBounds(left, top, right, bottom);
         }
-        
+
         if (mProgressDrawable != null) {
             mProgressDrawable.setBounds(0, 0, right, bottom);
         }
@@ -1519,20 +1572,20 @@
         setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
                 resolveSizeAndState(dh, heightMeasureSpec, 0));
     }
-    
+
     @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
         updateDrawableState();
     }
-        
+
     private void updateDrawableState() {
         int[] state = getDrawableState();
-        
+
         if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
             mProgressDrawable.setState(state);
         }
-        
+
         if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
             mIndeterminateDrawable.setState(state);
         }
@@ -1554,14 +1607,14 @@
     static class SavedState extends BaseSavedState {
         int progress;
         int secondaryProgress;
-        
+
         /**
          * Constructor called from {@link ProgressBar#onSaveInstanceState()}
          */
         SavedState(Parcelable superState) {
             super(superState);
         }
-        
+
         /**
          * Constructor called from {@link #CREATOR}
          */
@@ -1595,10 +1648,10 @@
         // Force our ancestor class to save its state
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        
+
         ss.progress = mProgress;
         ss.secondaryProgress = mSecondaryProgress;
-        
+
         return ss;
     }
 
@@ -1606,7 +1659,7 @@
     public void onRestoreInstanceState(Parcelable state) {
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        
+
         setProgress(ss.progress);
         setSecondaryProgress(ss.secondaryProgress);
     }
@@ -1622,7 +1675,7 @@
                 final int count = mRefreshData.size();
                 for (int i = 0; i < count; i++) {
                     final RefreshData rd = mRefreshData.get(i);
-                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
+                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, rd.animate);
                     rd.recycle();
                 }
                 mRefreshData.clear();
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 9b763c1..1e30bfa 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -518,6 +518,9 @@
         if (mIs24HourMode) {
             if (mIsOnInnerCircle) {
                 hours = hours % 12;
+                if (hours == 0) {
+                    hours = 12;
+                }
             } else {
                 if (hours != 0) {
                     hours += 12;
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 82b490e..c4a7c0a 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -314,6 +314,10 @@
         dispatchRatingChange(true);
     }
 
+    @Override
+    void animateSetProgress(int progress) {
+    }
+
     void dispatchRatingChange(boolean fromUser) {
         if (mOnRatingBarChangeListener != null) {
             mOnRatingBarChangeListener.onRatingChanged(this, getRating(),
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 90e80d3..4dd7e07 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -195,6 +195,11 @@
             LEFT_OF, RIGHT_OF, ALIGN_LEFT, ALIGN_RIGHT, START_OF, END_OF, ALIGN_START, ALIGN_END
     };
 
+    /**
+     * Used to indicate left/right/top/bottom should be inferred from constraints
+     */
+    private static final int VALUE_NOT_SET = Integer.MIN_VALUE;
+
     private View mBaselineView = null;
     private boolean mHasBaselineAlignedChild;
 
@@ -670,8 +675,8 @@
 
     /**
      * Measure a child. The child should have left, top, right and bottom information
-     * stored in its LayoutParams. If any of these values is -1 it means that the view
-     * can extend up to the corresponding edge.
+     * 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.
      *
      * @param child Child to measure
      * @param params LayoutParams associated with child
@@ -744,11 +749,11 @@
         int childSpecMode = 0;
         int childSpecSize = 0;
 
-        // Negative values in a mySize/myWidth/myWidth value in RelativeLayout
+        // Negative values in a mySize value in RelativeLayout
         // measurement is code for, "we got an unspecified mode in the
         // RelativeLayout's measure spec."
         if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
-            if (childStart >= 0 && childEnd >= 0) {
+            if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
                 // Constraints fixed both edges, so child has an exact size.
                 childSpecSize = Math.max(0, childEnd - childStart);
                 childSpecMode = MeasureSpec.EXACTLY;
@@ -771,17 +776,17 @@
 
         // If the view did not express a layout constraint for an edge, use
         // view's margins and our padding
-        if (tempStart < 0) {
+        if (tempStart == VALUE_NOT_SET) {
             tempStart = startPadding + startMargin;
         }
-        if (tempEnd < 0) {
+        if (tempEnd == VALUE_NOT_SET) {
             tempEnd = mySize - endPadding - endMargin;
         }
 
         // Figure out maximum size available to this view
         int maxAvailable = tempEnd - tempStart;
 
-        if (childStart >= 0 && childEnd >= 0) {
+        if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
             // Constraints fixed both edges, so child must be an exact size
             childSpecMode = MeasureSpec.EXACTLY;
             childSpecSize = maxAvailable;
@@ -828,13 +833,13 @@
         final int layoutDirection = getLayoutDirection();
         int[] rules = params.getRules(layoutDirection);
 
-        if (params.mLeft < 0 && params.mRight >= 0) {
+        if (params.mLeft == VALUE_NOT_SET && params.mRight != VALUE_NOT_SET) {
             // Right is fixed, but left varies
             params.mLeft = params.mRight - child.getMeasuredWidth();
-        } else if (params.mLeft >= 0 && params.mRight < 0) {
+        } else if (params.mLeft != VALUE_NOT_SET && params.mRight == VALUE_NOT_SET) {
             // Left is fixed, but right varies
             params.mRight = params.mLeft + child.getMeasuredWidth();
-        } else if (params.mLeft < 0 && params.mRight < 0) {
+        } else if (params.mLeft == VALUE_NOT_SET && params.mRight == VALUE_NOT_SET) {
             // Both left and right vary
             if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
                 if (!wrapContent) {
@@ -864,13 +869,13 @@
 
         int[] rules = params.getRules();
 
-        if (params.mTop < 0 && params.mBottom >= 0) {
+        if (params.mTop == VALUE_NOT_SET && params.mBottom != VALUE_NOT_SET) {
             // Bottom is fixed, but top varies
             params.mTop = params.mBottom - child.getMeasuredHeight();
-        } else if (params.mTop >= 0 && params.mBottom < 0) {
+        } else if (params.mTop != VALUE_NOT_SET && params.mBottom == VALUE_NOT_SET) {
             // Top is fixed, but bottom varies
             params.mBottom = params.mTop + child.getMeasuredHeight();
-        } else if (params.mTop < 0 && params.mBottom < 0) {
+        } else if (params.mTop == VALUE_NOT_SET && params.mBottom == VALUE_NOT_SET) {
             // Both top and bottom vary
             if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
                 if (!wrapContent) {
@@ -891,12 +896,14 @@
     private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) {
         RelativeLayout.LayoutParams anchorParams;
 
-        // -1 indicated a "soft requirement" in that direction. For example:
-        // left=10, right=-1 means the view must start at 10, but can go as far as it wants to the right
-        // left =-1, right=10 means the view must end at 10, but can go as far as it wants to the left
+        // VALUE_NOT_SET indicates a "soft requirement" in that direction. For example:
+        // left=10, right=VALUE_NOT_SET means the view must start at 10, but can go as far as it
+        // wants to the right
+        // left=VALUE_NOT_SET, right=10 means the view must end at 10, but can go as far as it
+        // wants to the left
         // left=10, right=20 means the left and right ends are both fixed
-        childParams.mLeft = -1;
-        childParams.mRight = -1;
+        childParams.mLeft = VALUE_NOT_SET;
+        childParams.mRight = VALUE_NOT_SET;
 
         anchorParams = getRelatedViewParams(rules, LEFT_OF);
         if (anchorParams != null) {
@@ -947,8 +954,8 @@
         int[] rules = childParams.getRules();
         RelativeLayout.LayoutParams anchorParams;
 
-        childParams.mTop = -1;
-        childParams.mBottom = -1;
+        childParams.mTop = VALUE_NOT_SET;
+        childParams.mBottom = VALUE_NOT_SET;
 
         anchorParams = getRelatedViewParams(rules, ABOVE);
         if (anchorParams != null) {
@@ -1222,9 +1229,6 @@
 
         private int mLeft, mTop, mRight, mBottom;
 
-        private int mStart = DEFAULT_MARGIN_RELATIVE;
-        private int mEnd = DEFAULT_MARGIN_RELATIVE;
-
         private boolean mRulesChanged = false;
         private boolean mIsRtlCompatibilityMode = false;
 
@@ -1601,14 +1605,6 @@
         @Override
         public void resolveLayoutDirection(int layoutDirection) {
             final boolean isLayoutRtl = isLayoutRtl();
-            if (isLayoutRtl) {
-                if (mStart != DEFAULT_MARGIN_RELATIVE) mRight = mStart;
-                if (mEnd != DEFAULT_MARGIN_RELATIVE) mLeft = mEnd;
-            } else {
-                if (mStart != DEFAULT_MARGIN_RELATIVE) mLeft = mStart;
-                if (mEnd != DEFAULT_MARGIN_RELATIVE) mRight = mEnd;
-            }
-
             if (hasRelativeRules() && layoutDirection != getLayoutDirection()) {
                 resolveRules(layoutDirection);
             }
diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java
index 53d0839..3bad235 100644
--- a/core/java/android/widget/SimpleMonthAdapter.java
+++ b/core/java/android/widget/SimpleMonthAdapter.java
@@ -142,14 +142,10 @@
             enabledDayRangeEnd = 31;
         }
 
-        drawingParams.put(SimpleMonthView.VIEW_PARAMS_SELECTED_DAY, selectedDay);
-        drawingParams.put(SimpleMonthView.VIEW_PARAMS_YEAR, year);
-        drawingParams.put(SimpleMonthView.VIEW_PARAMS_MONTH, month);
-        drawingParams.put(SimpleMonthView.VIEW_PARAMS_WEEK_START, mController.getFirstDayOfWeek());
-        drawingParams.put(SimpleMonthView.VIEW_PARAMS_ENABLEDDAYRANGE_START, enabledDayRangeStart);
-        drawingParams.put(SimpleMonthView.VIEW_PARAMS_ENABLEDDAYRANGE_END, enabledDayRangeEnd);
-        v.setMonthParams(drawingParams);
+        v.setMonthParams(selectedDay, month, year, mController.getFirstDayOfWeek(),
+                enabledDayRangeStart, enabledDayRangeEnd);
         v.invalidate();
+
         return v;
     }
 
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 7589711..ab6da7c 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -52,44 +52,6 @@
 class SimpleMonthView extends View {
     private static final String TAG = "SimpleMonthView";
 
-    /**
-     * These params can be passed into the view to control how it appears.
-     * {@link #VIEW_PARAMS_WEEK} is the only required field, though the default
-     * values are unlikely to fit most layouts correctly.
-     */
-    /**
-     * This sets the height of this week in pixels
-     */
-    static final String VIEW_PARAMS_HEIGHT = "height";
-    /**
-     * This specifies the position (or weeks since the epoch) of this week,
-     * calculated using
-     */
-    static final String VIEW_PARAMS_MONTH = "month";
-    /**
-     * This specifies the position (or weeks since the epoch) of this week,
-     * calculated using
-     */
-    static final String VIEW_PARAMS_YEAR = "year";
-    /**
-     * This sets one of the days in this view as selected {@link Time#SUNDAY}
-     * through {@link Time#SATURDAY}.
-     */
-    static final String VIEW_PARAMS_SELECTED_DAY = "selected_day";
-    /**
-     * Which day the week should start on. {@link Time#SUNDAY} through
-     * {@link Time#SATURDAY}.
-     */
-    static final String VIEW_PARAMS_WEEK_START = "week_start";
-    /**
-     * First enabled day.
-     */
-    static final String VIEW_PARAMS_ENABLEDDAYRANGE_START = "enabled_day_range_start";
-    /**
-     * Last enabled day.
-     */
-    static final String VIEW_PARAMS_ENABLEDDAYRANGE_END = "enabled_day_range_end";
-
     private static int DEFAULT_HEIGHT = 32;
     private static int MIN_HEIGHT = 10;
 
@@ -327,36 +289,38 @@
         drawDays(canvas);
     }
 
+    private static boolean isValidDay(int day) {
+        return (day >= Time.SUNDAY && day <= Time.SATURDAY);
+    }
+
     /**
-     * Sets all the parameters for displaying this week. The only required
-     * parameter is the week number. Other parameters have a default value and
-     * will only update if a new value is included, except for focus month,
-     * which will always default to no focus month if no value is passed in. See
-     * {@link #VIEW_PARAMS_HEIGHT} for more info on parameters.
+     * Sets all the parameters for displaying this week. Parameters have a default value and
+     * will only update if a new value is included, except for focus month, which will always
+     * default to no focus month if no value is passed in. The only required parameter is the
+     * week start.
      *
-     * @param params A map of the new parameters, see
-     *            {@link #VIEW_PARAMS_HEIGHT}
+     * @param selectedDay the selected day.
+     * @param month the month.
+     * @param year the year.
+     * @param weekStart which day the week should start on. {@link Time#SUNDAY} through
+     *        {@link Time#SATURDAY}.
+     * @param enabledDayStart the first enabled day.
+     * @param enabledDayEnd the last enabled day.
      */
-    void setMonthParams(HashMap<String, Integer> params) {
-        if (!params.containsKey(VIEW_PARAMS_MONTH) && !params.containsKey(VIEW_PARAMS_YEAR)) {
-            throw new InvalidParameterException(
-                    "You must specify the month and year for this view");
-        }
-        setTag(params);
-        // We keep the current value for any params not present
-        if (params.containsKey(VIEW_PARAMS_HEIGHT)) {
-            mRowHeight = params.get(VIEW_PARAMS_HEIGHT);
-            if (mRowHeight < MIN_HEIGHT) {
-                mRowHeight = MIN_HEIGHT;
-            }
-        }
-        if (params.containsKey(VIEW_PARAMS_SELECTED_DAY)) {
-            mSelectedDay = params.get(VIEW_PARAMS_SELECTED_DAY);
+    void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart,
+            int enabledDayEnd) {
+        if (mRowHeight < MIN_HEIGHT) {
+            mRowHeight = MIN_HEIGHT;
         }
 
-        // Allocate space for caching the day numbers and focus values
-        mMonth = params.get(VIEW_PARAMS_MONTH);
-        mYear = params.get(VIEW_PARAMS_YEAR);
+        if (isValidDay(selectedDay)) {
+            mSelectedDay = selectedDay;
+        }
+
+        if (month >= Calendar.JANUARY && month <= Calendar.DECEMBER) {
+            mMonth = month;
+        }
+        mYear = year;
 
         // Figure out what day today is
         final Time today = new Time(Time.getCurrentTimezone());
@@ -369,17 +333,17 @@
         mCalendar.set(Calendar.DAY_OF_MONTH, 1);
         mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK);
 
-        if (params.containsKey(VIEW_PARAMS_WEEK_START)) {
-            mWeekStart = params.get(VIEW_PARAMS_WEEK_START);
+        if (isValidDay(weekStart)) {
+            mWeekStart = weekStart;
         } else {
             mWeekStart = mCalendar.getFirstDayOfWeek();
         }
 
-        if (params.containsKey(VIEW_PARAMS_ENABLEDDAYRANGE_START)) {
-            mEnabledDayStart = params.get(VIEW_PARAMS_ENABLEDDAYRANGE_START);
+        if (enabledDayStart > 0 && enabledDayEnd < 32) {
+            mEnabledDayStart = enabledDayStart;
         }
-        if (params.containsKey(VIEW_PARAMS_ENABLEDDAYRANGE_END)) {
-            mEnabledDayEnd = params.get(VIEW_PARAMS_ENABLEDDAYRANGE_END);
+        if (enabledDayEnd > 0 && enabledDayEnd < 32 && enabledDayEnd >= enabledDayStart) {
+            mEnabledDayEnd = enabledDayEnd;
         }
 
         mNumCells = getDaysInMonth(mMonth, mYear);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index fac0eb2..52618cc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -657,6 +657,7 @@
         int shadowcolor = 0;
         float dx = 0, dy = 0, r = 0;
         boolean elegant = false;
+        float letterSpacing = 0;
 
         final Resources.Theme theme = context.getTheme();
 
@@ -737,6 +738,10 @@
                 case com.android.internal.R.styleable.TextAppearance_elegantTextHeight:
                     elegant = appearance.getBoolean(attr, false);
                     break;
+
+                case com.android.internal.R.styleable.TextAppearance_letterSpacing:
+                    letterSpacing = appearance.getFloat(attr, 0);
+                    break;
                 }
             }
 
@@ -1078,6 +1083,10 @@
             case com.android.internal.R.styleable.TextView_elegantTextHeight:
                 elegant = a.getBoolean(attr, false);
                 break;
+
+            case com.android.internal.R.styleable.TextView_letterSpacing:
+                letterSpacing = a.getFloat(attr, 0);
+                break;
             }
         }
         a.recycle();
@@ -1259,6 +1268,7 @@
         }
         setRawTextSize(textSize);
         setElegantTextHeight(elegant);
+        setLetterSpacing(letterSpacing);
 
         if (allCaps) {
             setTransformationMethod(new AllCapsTransformationMethod(getContext()));
@@ -2487,6 +2497,11 @@
                 com.android.internal.R.styleable.TextAppearance_elegantTextHeight, false));
         }
 
+        if (appearance.hasValue(com.android.internal.R.styleable.TextAppearance_letterSpacing)) {
+            setLetterSpacing(appearance.getFloat(
+                com.android.internal.R.styleable.TextAppearance_letterSpacing, 0));
+        }
+
         appearance.recycle();
     }
 
@@ -2667,6 +2682,41 @@
     }
 
     /**
+     * @return the extent by which text is currently being letter-spaced.
+     * This will normally be 0.
+     *
+     * @see #setLetterSpacing(float)
+     * @hide
+     */
+    public float getLetterSpacing() {
+        return mTextPaint.getLetterSpacing();
+    }
+
+    /**
+     * Sets text letter-spacing.  The value is in 'EM' units.  Typical values
+     * for slight expansion will be around 0.05.  Negative values tighten text.
+     *
+     * @see #getLetterSpacing()
+     * @see Paint#setFlags
+     *
+     * @attr ref android.R.styleable#TextView_letterSpacing
+     * @hide
+     */
+    @android.view.RemotableViewMethod
+    public void setLetterSpacing(float letterSpacing) {
+        if (letterSpacing != mTextPaint.getLetterSpacing()) {
+            mTextPaint.setLetterSpacing(letterSpacing);
+
+            if (mLayout != null) {
+                nullLayouts();
+                requestLayout();
+                invalidate();
+            }
+        }
+    }
+
+
+    /**
      * Sets the text color for all the states (normal, selected,
      * focused) to be this color.
      *
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 71102e8..0b15eb6 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActionBar;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -654,27 +655,13 @@
     }
 
     /**
-     * Set the icon to use for the toolbar's navigation button.
-     *
-     * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
-     * will make the navigation button visible.</p>
-     *
-     * <p>If you use a navigation icon you should also set a description for its action using
-     * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p>
-     *
-     * @param resId Resource ID of a drawable to set
-     */
-    public void setNavigationIcon(int resId) {
-        setNavigationIcon(getContext().getDrawable(resId));
-    }
-
-    /**
      * Retrieve the currently configured content description for the navigation button view.
      * This will be used to describe the navigation action to users through mechanisms such
      * as screen readers or tooltips.
      *
      * @return The navigation button's content description
      */
+    @Nullable
     public CharSequence getNavigationContentDescription() {
         return mNavButtonView != null ? mNavButtonView.getContentDescription() : null;
     }
@@ -684,11 +671,11 @@
      * description will be read via screen readers or other accessibility systems to explain
      * the action of the navigation button.
      *
-     * @param description Content description to set
+     * @param resId Resource ID of a content description string to set, or 0 to
+     *              clear the description
      */
-    public void setNavigationContentDescription(CharSequence description) {
-        ensureNavButtonView();
-        mNavButtonView.setContentDescription(description);
+    public void setNavigationContentDescription(int resId) {
+        setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null);
     }
 
     /**
@@ -696,11 +683,16 @@
      * description will be read via screen readers or other accessibility systems to explain
      * the action of the navigation button.
      *
-     * @param resId Resource ID of a content description string to set
+     * @param description Content description to set, or <code>null</code> to
+     *                    clear the content description
      */
-    public void setNavigationContentDescription(int resId) {
-        ensureNavButtonView();
-        mNavButtonView.setContentDescription(resId != 0 ? getContext().getText(resId) : null);
+    public void setNavigationContentDescription(@Nullable CharSequence description) {
+        if (!TextUtils.isEmpty(description)) {
+            ensureNavButtonView();
+        }
+        if (mNavButtonView != null) {
+            mNavButtonView.setContentDescription(description);
+        }
     }
 
     /**
@@ -710,11 +702,28 @@
      * will make the navigation button visible.</p>
      *
      * <p>If you use a navigation icon you should also set a description for its action using
-     * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p>
+     * {@link #setNavigationContentDescription(int)}. This is used for accessibility and
+     * tooltips.</p>
      *
-     * @param icon Drawable to set
+     * @param resId Resource ID of a drawable to set
      */
-    public void setNavigationIcon(Drawable icon) {
+    public void setNavigationIcon(int resId) {
+        setNavigationIcon(getContext().getDrawable(resId));
+    }
+
+    /**
+     * Set the icon to use for the toolbar's navigation button.
+     *
+     * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
+     * will make the navigation button visible.</p>
+     *
+     * <p>If you use a navigation icon you should also set a description for its action using
+     * {@link #setNavigationContentDescription(int)}. This is used for accessibility and
+     * tooltips.</p>
+     *
+     * @param icon Drawable to set, may be null to clear the icon
+     */
+    public void setNavigationIcon(@Nullable Drawable icon) {
         if (icon != null) {
             ensureNavButtonView();
             if (mNavButtonView.getParent() == null) {
@@ -733,40 +742,12 @@
      *
      * @return The navigation icon drawable
      */
+    @Nullable
     public Drawable getNavigationIcon() {
         return mNavButtonView != null ? mNavButtonView.getDrawable() : null;
     }
 
     /**
-     * Set a description for the navigation button.
-     *
-     * <p>This description string is used for accessibility, tooltips and other facilities
-     * to improve discoverability.</p>
-     *
-     * @param resId Resource ID of a string to set
-     */
-    public void setNavigationDescription(int resId) {
-        setNavigationDescription(getContext().getText(resId));
-    }
-
-    /**
-     * Set a description for the navigation button.
-     *
-     * <p>This description string is used for accessibility, tooltips and other facilities
-     * to improve discoverability.</p>
-     *
-     * @param description String to set as the description
-     */
-    public void setNavigationDescription(CharSequence description) {
-        if (!TextUtils.isEmpty(description)) {
-            ensureNavButtonView();
-        }
-        if (mNavButtonView != null) {
-            mNavButtonView.setContentDescription(description);
-        }
-    }
-
-    /**
      * Set a listener to respond to navigation events.
      *
      * <p>This listener will be called whenever the user clicks the navigation button
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 9ff2cf4..a52dd48 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -40,8 +40,6 @@
     int checkAudioOperation(int code, int usage, int uid, String packageName);
     void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
 
-    void setDeviceOwner(String packageName);
-    void setProfileOwner(String packageName, int userHandle);
     void setUserRestrictions(in Bundle restrictions, int userHandle);
     void removeUser(int userHandle);
 
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 7d5abd2..22ec4be 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -33,19 +33,24 @@
     void finish(IBinder token);
 
     /**
-     * Lists the registered Sound models for keyphrase detection.
+     * Lists the registered Sound model for keyphrase detection.
      * May be null if no matching sound models exist.
-     *
-     * @param service The current voice interaction service.
      */
-    List<SoundTrigger.KeyphraseSoundModel> listRegisteredKeyphraseSoundModels(
-            in IVoiceInteractionService service);
+    SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId);
     /**
      * Updates the given keyphrase sound model. Adds the model if it doesn't exist currently.
      */
     int updateKeyphraseSoundModel(in SoundTrigger.KeyphraseSoundModel model);
+    /**
+     * Deletes the given keyphrase sound model.
+     */
+    int deleteKeyphraseSoundModel(int keyphraseId);
 
     /**
+     * Indicates if there's a keyphrase sound model available for the given keyphrase ID.
+     */
+    boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId);
+    /**
      * Gets the properties of the DSP hardware on this device, null if not present.
      */
     SoundTrigger.ModuleProperties getDspModuleProperties(in IVoiceInteractionService service);
@@ -53,7 +58,7 @@
      * Starts a recognition for the given keyphrase.
      */
     int startRecognition(in IVoiceInteractionService service, int keyphraseId,
-            in SoundTrigger.KeyphraseSoundModel soundModel, in IRecognitionStatusCallback callback,
+            in IRecognitionStatusCallback callback,
             in SoundTrigger.RecognitionConfig recognitionConfig);
     /**
      * Stops a recognition for the given keyphrase.
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 01e5d40..1c01353 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -16,24 +16,25 @@
 
 package com.android.internal.app;
 
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+
 import android.app.Activity;
+import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.os.Bundle;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.UserInfo;
+import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.app.ActivityManagerNative;
-import android.os.RemoteException;
 import android.util.Slog;
+import android.widget.Toast;
 import java.util.List;
 import java.util.Set;
 
-
-
-
 /*
  * This is used in conjunction with the {@link setCrossProfileIntentFilter} method of
  * {@link DevicePolicyManager} to enable intents to be passed in and out of a managed profile.
@@ -56,13 +57,17 @@
 
         String className = intentReceived.getComponent().getClassName();
         final UserHandle userDest;
+        final int userMessageId;
 
         if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
+            userMessageId = com.android.internal.R.string.forward_intent_to_owner;
             userDest = UserHandle.OWNER;
         } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+            userMessageId = com.android.internal.R.string.forward_intent_to_work;
             userDest = getManagedProfile();
         } else {
             Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
+            userMessageId = -1;
             userDest = null;
         }
         if (userDest == null) { // This covers the case where there is no managed profile.
@@ -84,8 +89,20 @@
             Slog.e(TAG, "PackageManagerService is dead?");
         }
         if (canForward) {
-            newIntent.prepareToLeaveUser(callingUserId);
+            newIntent.setContentUserHint(callingUserId);
+
+            final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser(
+                        newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier());
+
+            // Only show a disclosure if this is a normal (non-OS) app
+            final boolean shouldShowDisclosure =
+                    !UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID);
+
             startActivityAsUser(newIntent, userDest);
+
+            if (shouldShowDisclosure) {
+                Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show();
+            }
         } else {
             Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
                     + callingUserId + " to user " + userDest.getIdentifier());
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 1bcb684..298dd44 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -154,7 +154,7 @@
 
     @Override
     public void setHomeActionContentDescription(CharSequence description) {
-        mToolbar.setNavigationDescription(description);
+        mToolbar.setNavigationContentDescription(description);
     }
 
     @Override
@@ -164,7 +164,7 @@
 
     @Override
     public void setHomeActionContentDescription(int resId) {
-        mToolbar.setNavigationDescription(resId);
+        mToolbar.setNavigationContentDescription(resId);
     }
 
     @Override
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index fdd24a6..52485dd 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -54,8 +54,8 @@
         public final CharSequence mSubtypeName;
         public final InputMethodInfo mImi;
         public final int mSubtypeId;
-        private final boolean mIsSystemLocale;
-        private final boolean mIsSystemLanguage;
+        public final boolean mIsSystemLocale;
+        public final boolean mIsSystemLanguage;
 
         public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
                 InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) {
@@ -68,8 +68,28 @@
                 mIsSystemLanguage = false;
             } else {
                 mIsSystemLocale = subtypeLocale.equals(systemLocale);
-                mIsSystemLanguage = mIsSystemLocale
-                        || subtypeLocale.startsWith(systemLocale.substring(0, 2));
+                if (mIsSystemLocale) {
+                    mIsSystemLanguage = true;
+                } else {
+                    // TODO: Use Locale#getLanguage or Locale#toLanguageTag
+                    final String systemLanguage = parseLanguageFromLocaleString(systemLocale);
+                    final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale);
+                    mIsSystemLanguage = systemLanguage.length() >= 2 &&
+                            systemLanguage.equals(subtypeLanguage);
+                }
+            }
+        }
+
+        /**
+         * Returns the language component of a given locale string.
+         * TODO: Use {@link Locale#getLanguage()} instead.
+         */
+        private static String parseLanguageFromLocaleString(final String locale) {
+            final int idx = locale.indexOf('_');
+            if (idx < 0) {
+                return locale;
+            } else {
+                return locale.substring(0, idx);
             }
         }
 
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 73d3738..0099269 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -27,6 +27,7 @@
 import android.net.RouteInfo;
 import android.net.LinkAddress;
 
+import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.util.List;
 import java.util.ArrayList;
@@ -73,6 +74,18 @@
     public PendingIntent configureIntent;
     public long startTime = -1;
     public boolean legacy;
+    public boolean blocking;
+    public boolean allowBypass;
+    public boolean allowIPv4;
+    public boolean allowIPv6;
+
+    public void updateAllowedFamilies(InetAddress address) {
+        if (address instanceof Inet4Address) {
+            allowIPv4 = true;
+        } else {
+            allowIPv6 = true;
+        }
+    }
 
     public void addLegacyRoutes(String routesStr) {
         if (routesStr.trim().equals("")) {
@@ -85,6 +98,7 @@
             RouteInfo info = new RouteInfo(new LinkAddress
                     (InetAddress.parseNumericAddress(split[0]), Integer.parseInt(split[1])), null);
             this.routes.add(info);
+            updateAllowedFamilies(info.getDestination().getAddress());
         }
     }
 
@@ -99,6 +113,7 @@
             LinkAddress addr = new LinkAddress(InetAddress.parseNumericAddress(split[0]),
                     Integer.parseInt(split[1]));
             this.addresses.add(addr);
+            updateAllowedFamilies(addr.getAddress());
         }
     }
 
@@ -120,6 +135,10 @@
         out.writeParcelable(configureIntent, flags);
         out.writeLong(startTime);
         out.writeInt(legacy ? 1 : 0);
+        out.writeInt(blocking ? 1 : 0);
+        out.writeInt(allowBypass ? 1 : 0);
+        out.writeInt(allowIPv4 ? 1 : 0);
+        out.writeInt(allowIPv6 ? 1 : 0);
     }
 
     public static final Parcelable.Creator<VpnConfig> CREATOR =
@@ -138,6 +157,10 @@
             config.configureIntent = in.readParcelable(null);
             config.startTime = in.readLong();
             config.legacy = in.readInt() != 0;
+            config.blocking = in.readInt() != 0;
+            config.allowBypass = in.readInt() != 0;
+            config.allowIPv4 = in.readInt() != 0;
+            config.allowIPv6 = in.readInt() != 0;
             return config;
         }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 84bd443..969c0db 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -34,6 +34,7 @@
             boolean showImeSwitcher);
     void setHardKeyboardStatus(boolean available, boolean enabled);
     void setWindowState(int window, int state);
+    void buzzBeepBlinked();
 
     void showRecentApps(boolean triggeredFromAltTab);
     void hideRecentApps(boolean triggeredFromAltTab);
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index c0d1e88..414b7bc 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.util;
 
+import java.util.Collection;
+
 /**
  * Simple static methods to be called at the start of your own methods to verify
  * correct arguments and state.
@@ -210,7 +212,7 @@
     }
 
     /**
-     * Ensures that the array is not {@code null}, and none if its elements are {@code null}.
+     * Ensures that the array is not {@code null}, and none of its elements are {@code null}.
      *
      * @param value an array of boxed objects
      * @param valueName the name of the argument to use if the check fails
@@ -235,6 +237,57 @@
     }
 
     /**
+     * Ensures that the {@link Collection} is not {@code null}, and none of its elements are
+     * {@code null}.
+     *
+     * @param value a {@link Collection} of boxed objects
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated {@link Collection}
+     *
+     * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
+     */
+    public static <T> Collection<T> checkCollectionElementsNotNull(final Collection<T> value,
+            final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+
+        long ctr = 0;
+        for (T elem : value) {
+            if (elem == null) {
+                throw new NullPointerException(
+                        String.format("%s[%d] must not be null", valueName, ctr));
+            }
+            ++ctr;
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the {@link Collection} is not {@code null}, and contains at least one element.
+     *
+     * @param value a {@link Collection} of boxed elements.
+     * @param valueName the name of the argument to use if the check fails.
+
+     * @return the validated {@link Collection}
+     *
+     * @throws NullPointerException if the {@code value} was {@code null}
+     * @throws IllegalArgumentException if the {@code value} was empty
+     */
+    public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value,
+            final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+        if (value.isEmpty()) {
+            throw new IllegalArgumentException(valueName + " is empty");
+        }
+        return value;
+    }
+
+    /**
      * Ensures that all elements in the argument floating point array are within the inclusive range
      *
      * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index af966b1..d9ebc25 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -48,6 +48,8 @@
     public static final int BASE_WIFI_CONTROLLER                                    = 0x00026000;
     public static final int BASE_WIFI_SCANNER                                       = 0x00027000;
     public static final int BASE_WIFI_SCANNER_SERVICE                               = 0x00027100;
+    public static final int BASE_WIFI_RTT_MANAGER                                   = 0x00027200;
+    public static final int BASE_WIFI_RTT_SERVICE                                   = 0x00027300;
     public static final int BASE_WIFI_PASSPOINT_MANAGER                             = 0x00028000;
     public static final int BASE_WIFI_PASSPOINT_SERVICE                             = 0x00028100;
     public static final int BASE_DHCP                                               = 0x00030000;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d60f787..7e8d828 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -256,15 +256,11 @@
                 getCurrentOrCallingUserId());
     }
 
-    /**
-     * Returns the actual password mode, as set by keyguard after updating the password.
-     *
-     * @return
-     */
     public void reportFailedPasswordAttempt() {
-        getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
-        getTrustManager().reportUnlockAttempt(false /* authenticated */,
-                getCurrentOrCallingUserId());
+        int userId = getCurrentOrCallingUserId();
+        getDevicePolicyManager().reportFailedPasswordAttempt(userId);
+        getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
+        getTrustManager().reportRequireCredentialEntry(userId);
     }
 
     public void reportSuccessfulPasswordAttempt() {
@@ -359,7 +355,8 @@
      * @return Whether the password matches any in the history.
      */
     public boolean checkPasswordHistory(String password) {
-        String passwordHashString = new String(passwordToHash(password));
+        String passwordHashString = new String(
+                passwordToHash(password, getCurrentOrCallingUserId()));
         String passwordHistory = getString(PASSWORD_HISTORY_KEY);
         if (passwordHistory == null) {
             return false;
@@ -828,7 +825,7 @@
                 if (passwordHistoryLength == 0) {
                     passwordHistory = "";
                 } else {
-                    byte[] hash = passwordToHash(password);
+                    byte[] hash = passwordToHash(password, userHandle);
                     passwordHistory = new String(hash) + "," + passwordHistory;
                     // Cut it to contain passwordHistoryLength hashes
                     // and passwordHistoryLength -1 commas.
@@ -944,13 +941,13 @@
         }
     }
 
-    private String getSalt() {
-        long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0);
+    private String getSalt(int userId) {
+        long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
         if (salt == 0) {
             try {
                 salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
-                setLong(LOCK_PASSWORD_SALT_KEY, salt);
-                Log.v(TAG, "Initialized lock password salt");
+                setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
+                Log.v(TAG, "Initialized lock password salt for user: " + userId);
             } catch (NoSuchAlgorithmException e) {
                 // Throw an exception rather than storing a password we'll never be able to recover
                 throw new IllegalStateException("Couldn't get SecureRandom number", e);
@@ -966,14 +963,14 @@
      * @param password the gesture pattern.
      * @return the hash of the pattern in a byte array.
      */
-    public byte[] passwordToHash(String password) {
+    public byte[] passwordToHash(String password, int userId) {
         if (password == null) {
             return null;
         }
         String algo = null;
         byte[] hashed = null;
         try {
-            byte[] saltedPassword = (password + getSalt()).getBytes();
+            byte[] saltedPassword = (password + getSalt(userId)).getBytes();
             byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
             byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
             hashed = (toHex(sha1) + toHex(md5)).getBytes();
@@ -1336,6 +1333,14 @@
         return true;
     }
 
+    private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
+        try {
+            return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
+        } catch (RemoteException re) {
+            return defaultValue;
+        }
+    }
+
     private long getLong(String secureSettingKey, long defaultValue) {
         try {
             return getLockSettings().getLong(secureSettingKey, defaultValue,
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 7b5395b..480383b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -23,7 +23,6 @@
 
 LOCAL_SRC_FILES:= \
 	AndroidRuntime.cpp \
-	Time.cpp \
 	com_android_internal_content_NativeLibraryHelper.cpp \
 	com_google_android_gles_jni_EGLImpl.cpp \
 	com_google_android_gles_jni_GLImpl.cpp.arm \
@@ -81,7 +80,6 @@
 	android_net_NetUtils.cpp \
 	android_net_TrafficStats.cpp \
 	android_nio_utils.cpp \
-	android_text_format_Time.cpp \
 	android_util_AssetManager.cpp \
 	android_util_Binder.cpp \
 	android_util_EventLog.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 92a8fca..3a02ab9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -144,7 +144,6 @@
 extern int register_android_database_SQLiteGlobal(JNIEnv* env);
 extern int register_android_database_SQLiteDebug(JNIEnv* env);
 extern int register_android_nio_utils(JNIEnv* env);
-extern int register_android_text_format_Time(JNIEnv* env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_MessageQueue(JNIEnv* env);
 extern int register_android_os_Parcel(JNIEnv* env);
@@ -1223,7 +1222,6 @@
     REG_JNI(register_android_util_EventLog),
     REG_JNI(register_android_util_Log),
     REG_JNI(register_android_util_FloatMath),
-    REG_JNI(register_android_text_format_Time),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
     REG_JNI(register_android_content_XmlBlock),
diff --git a/core/jni/Time.cpp b/core/jni/Time.cpp
deleted file mode 100644
index f3037f3..0000000
--- a/core/jni/Time.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-#include "TimeUtils.h"
-#include <stdio.h>
-#include <cutils/tztime.h>
-
-namespace android {
-
-static void
-dump(const Time& t)
-{
-    #ifdef HAVE_TM_GMTOFF
-        long tm_gmtoff = t.t.tm_gmtoff;
-    #else
-        long tm_gmtoff = 0;
-    #endif
-    printf("%04d-%02d-%02d %02d:%02d:%02d (%d,%ld,%d,%d)\n",
-            t.t.tm_year+1900, t.t.tm_mon+1, t.t.tm_mday,
-            t.t.tm_hour, t.t.tm_min, t.t.tm_sec,
-            t.t.tm_isdst, tm_gmtoff, t.t.tm_wday, t.t.tm_yday);
-}
-
-Time::Time()
-{
-    t.tm_sec = 0;
-    t.tm_min = 0;
-    t.tm_hour = 0;
-    t.tm_mday = 0;
-    t.tm_mon = 0;
-    t.tm_year = 0;
-    t.tm_wday = 0;
-    t.tm_yday = 0;
-    t.tm_isdst = -1; // we don't know, so let the C library determine
-    #ifdef HAVE_TM_GMTOFF
-        t.tm_gmtoff = 0;
-    #endif
-}
-
-
-#define COMPARE_FIELD(field) do { \
-        int diff = a.t.field - b.t.field; \
-        if (diff != 0) return diff; \
-    } while(0)
-
-int
-Time::compare(Time& a, Time& b)
-{
-    if (0 == strcmp(a.timezone, b.timezone)) {
-        // if the timezones are the same, we can easily compare the two
-        // times.  Otherwise, convert to milliseconds and compare that.
-        // This requires that object be normalized.
-        COMPARE_FIELD(tm_year);
-        COMPARE_FIELD(tm_mon);
-        COMPARE_FIELD(tm_mday);
-        COMPARE_FIELD(tm_hour);
-        COMPARE_FIELD(tm_min);
-        COMPARE_FIELD(tm_sec);
-        return 0;
-    } else {
-        int64_t am = a.toMillis(false /* use isDst */);
-        int64_t bm = b.toMillis(false /* use isDst */);
-        int64_t diff = am-bm;
-        return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
-    }
-}
-
-static const int DAYS_PER_MONTH[] = {
-                        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-                    };
-
-static inline int days_this_month(int year, int month)
-{
-    int n = DAYS_PER_MONTH[month];
-    if (n != 28) {
-        return n;
-    } else {
-        int y = year;
-        return ((y%4)==0&&((y%100)!=0||(y%400)==0)) ? 29 : 28;
-    }
-}
-
-void 
-Time::switchTimezone(const char* timezone)
-{
-    time_t seconds = mktime_tz(&(this->t), this->timezone);
-    localtime_tz(&seconds, &(this->t), timezone);
-}
-
-String8 
-Time::format(const char *format, const struct strftime_locale *locale) const
-{
-    char buf[257];
-    int n = strftime_tz(buf, 257, format, &(this->t), locale);
-    if (n > 0) {
-        return String8(buf);
-    } else {
-        return String8();
-    }
-}
-
-static inline short
-tochar(int n)
-{
-    return (n >= 0 && n <= 9) ? ('0'+n) : ' ';
-}
-
-static inline short
-next_char(int *m, int k)
-{
-    int n = *m / k;
-    *m = *m % k;
-    return tochar(n);
-}
-
-void
-Time::format2445(short* buf, bool hasTime) const
-{
-    int n;
-
-    n = t.tm_year+1900;
-    buf[0] = next_char(&n, 1000);
-    buf[1] = next_char(&n, 100);
-    buf[2] = next_char(&n, 10);
-    buf[3] = tochar(n);
-
-    n = t.tm_mon+1;
-    buf[4] = next_char(&n, 10);
-    buf[5] = tochar(n);
-
-    n = t.tm_mday;
-    buf[6] = next_char(&n, 10);
-    buf[7] = tochar(n);
-
-    if (hasTime) {
-      buf[8] = 'T';
-
-      n = t.tm_hour;
-      buf[9] = next_char(&n, 10);
-      buf[10] = tochar(n);
-      
-      n = t.tm_min;
-      buf[11] = next_char(&n, 10);
-      buf[12] = tochar(n);
-      
-      n = t.tm_sec;
-      buf[13] = next_char(&n, 10);
-      buf[14] = tochar(n);
-      bool inUtc = strcmp("UTC", timezone) == 0;
-      if (inUtc) {
-          buf[15] = 'Z';
-      }
-    }
-}
-
-String8 
-Time::toString() const
-{
-    String8 str;
-    char* s = str.lockBuffer(150);
-    #ifdef HAVE_TM_GMTOFF
-        long tm_gmtoff = t.tm_gmtoff;
-    #else
-        long tm_gmtoff = 0;
-    #endif
-    sprintf(s, "%04d%02d%02dT%02d%02d%02d%s(%d,%d,%ld,%d,%d)", 
-            t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min,
-            t.tm_sec, timezone, t.tm_wday, t.tm_yday, tm_gmtoff, t.tm_isdst,
-            (int)(((Time*)this)->toMillis(false /* use isDst */)/1000));
-    str.unlockBuffer();
-    return str;
-}
-
-void 
-Time::setToNow()
-{
-    time_t seconds;
-    time(&seconds);
-    localtime_tz(&seconds, &(this->t), this->timezone);
-}
-
-int64_t 
-Time::toMillis(bool ignoreDst)
-{
-    if (ignoreDst) {
-        this->t.tm_isdst = -1;
-    }
-    int64_t r = mktime_tz(&(this->t), this->timezone);
-    if (r == -1)
-        return -1;
-    return r * 1000;
-}
-
-void 
-Time::set(int64_t millis)
-{
-    time_t seconds = millis / 1000;
-    localtime_tz(&seconds, &(this->t), this->timezone);
-}
-
-}; // namespace android
-
diff --git a/core/jni/TimeUtils.h b/core/jni/TimeUtils.h
deleted file mode 100644
index b19e021..0000000
--- a/core/jni/TimeUtils.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_TIME_H
-#define ANDROID_TIME_H
-
-#include <time.h>
-#include <cutils/tztime.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-namespace android {
-
-/*
- * This class is the core implementation of the android.util.Time java
- * class.  It doesn't implement some of the methods that are implemented
- * in Java.  They could be done here, but it's not expected that this class
- * will be used.  If that assumption is incorrect, feel free to update this
- * file.  The reason to do it here is to not mix the implementation of this
- * class and the jni glue code.
- */
-class Time
-{
-public:
-    struct tm t;
-
-    // this object doesn't own this string
-    const char *timezone;
-
-    enum {
-        SEC = 1,
-        MIN = 2,
-        HOUR = 3,
-        MDAY = 4,
-        MON = 5,
-        YEAR = 6,
-        WDAY = 7,
-        YDAY = 8
-    };
-
-    static int compare(Time& a, Time& b);
-
-    Time();
-
-    void switchTimezone(const char *timezone);
-    String8 format(const char *format, const struct strftime_locale *locale) const;
-    void format2445(short* buf, bool hasTime) const;
-    String8 toString() const;
-    void setToNow();
-    int64_t toMillis(bool ignoreDst);
-    void set(int64_t millis);
-
-    inline void set(int sec, int min, int hour, int mday, int mon, int year,
-            int isdst)
-    {
-        this->t.tm_sec = sec;
-        this->t.tm_min = min;
-        this->t.tm_hour = hour;
-        this->t.tm_mday = mday;
-        this->t.tm_mon = mon;
-        this->t.tm_year = year;
-        this->t.tm_isdst = isdst;
-#ifdef HAVE_TM_GMTOFF
-        this->t.tm_gmtoff = 0;
-#endif
-        this->t.tm_wday = 0;
-        this->t.tm_yday = 0;
-    }
-};
-
-}; // namespace android
-
-#endif // ANDROID_TIME_H
diff --git a/core/jni/android/graphics/Canvas.h b/core/jni/android/graphics/Canvas.h
index 317f69d..2577a90 100644
--- a/core/jni/android/graphics/Canvas.h
+++ b/core/jni/android/graphics/Canvas.h
@@ -14,125 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GRAPHICS_CANVAS_H
-#define ANDROID_GRAPHICS_CANVAS_H
-
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkMatrix.h"
-
-namespace android {
-
-// TODO: move this further up the stack so that all interaction with minikin
-//       happens prior to calling into this interface
-class Paint;
-class TypefaceImpl;
-
-class Canvas {
-public:
-    virtual ~Canvas() {};
-
-    static Canvas* create_canvas(SkBitmap* bitmap);
-    static Canvas* create_canvas(SkCanvas* skiaCanvas);
-
-    // TODO: enable HWUI to either create similar canvas wrapper or subclass
-    //       directly from Canvas
-    //static Canvas* create_canvas(uirenderer::Renderer* renderer);
-
-    // TODO: this is a temporary affordance until all necessary logic can be
-    //       moved within this interface! Further, the return value should
-    //       NOT be unref'd and is valid until this canvas is destroyed or a
-    //       new bitmap is set.
-    virtual SkCanvas* getSkCanvas() = 0;
-
-    virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0;
-
-    virtual bool isOpaque() = 0;
-    virtual int width() = 0;
-    virtual int height() = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
-    // Save (layer)
-    virtual int getSaveCount() const = 0;
-    virtual int save(SkCanvas::SaveFlags flags) = 0;
-    virtual void restore() = 0;
-    virtual void restoreToCount(int saveCount) = 0;
-
-    virtual int saveLayer(float left, float top, float right, float bottom,
-                const Paint* paint, SkCanvas::SaveFlags flags) = 0;
-    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags) = 0;
-
-    // Matrix
-    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
-    virtual void setMatrix(const SkMatrix& matrix) = 0;
-
-    virtual void concat(const SkMatrix& matrix) = 0;
-    virtual void rotate(float degrees) = 0;
-    virtual void scale(float sx, float sy) = 0;
-    virtual void skew(float sx, float sy) = 0;
-    virtual void translate(float dx, float dy) = 0;
-
-    // clip
-    virtual bool getClipBounds(SkRect* outRect) const = 0;
-    virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
-    virtual bool quickRejectPath(const SkPath& path) const = 0;
-
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
-
-    // filters
-    virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
-    virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
-    virtual void drawPaint(const Paint& paint) = 0;
-
-    // Geometry
-    virtual void drawPoint(float x, float y, const Paint& paint) = 0;
-    virtual void drawPoints(const float* points, int count, const Paint& paint) = 0;
-    virtual void drawLine(float startX, float startY, float stopX, float stopY,
-                const Paint& paint) = 0;
-    virtual void drawLines(const float* points, int count, const Paint& paint) = 0;
-    virtual void drawRect(float left, float top, float right, float bottom,
-            const Paint& paint) = 0;
-    virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const Paint& paint) = 0;
-    virtual void drawCircle(float x, float y, float radius, const Paint& paint) = 0;
-    virtual void drawOval(float left, float top, float right, float bottom,
-            const Paint& paint) = 0;
-    virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const Paint& paint) = 0;
-    virtual void drawPath(const SkPath& path, const Paint& paint) = 0;
-    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
-                              const float* verts, const float* tex, const int* colors,
-                              const uint16_t* indices, int indexCount, const Paint& paint) = 0;
-
-    // Bitmap-based
-    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
-            const Paint* paint) = 0;
-    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
-            const Paint* paint) = 0;
-    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const Paint* paint) = 0;
-    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const Paint* paint) = 0;
-
-    // Text
-    virtual void drawText(const uint16_t* text, int start, int count, int contextCount,
-            float x, float y, int bidiFlags, const Paint& paint,
-            TypefaceImpl* typeface) = 0;
-    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
-            int posCount, const Paint& paint) = 0;
-    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-            float hOffset, float vOffset, const Paint& paint) = 0;
-};
-
-}; // namespace android
-#endif // ANDROID_GRAPHICS_CANVAS_H
+// This header is shared with other libraries and as such is located in a
+// separate directory.
+#include <private/graphics/Canvas.h>
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index c66437a..2ad8330 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -29,6 +29,8 @@
 namespace android {
 
 // Do an sprintf starting at offset n, abort on overflow
+static int snprintfcat(char* buf, int off, int size, const char* format, ...)
+        __attribute__((__format__(__printf__, 4, 5)));
 static int snprintfcat(char* buf, int off, int size, const char* format, ...) {
     va_list args;
     va_start(args, format);
@@ -38,28 +40,29 @@
     return off + n;
 }
 
-std::string MinikinUtils::setLayoutProperties(Layout* layout, const Paint* paint, int bidiFlags,
-        TypefaceImpl* typeface) {
+void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
+        const uint16_t* buf, size_t start, size_t count, size_t bufSize) {
     TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
     layout->setFontCollection(resolvedFace->fFontCollection);
     FontStyle style = resolvedFace->fStyle;
-    char css[256];
+    char css[512];
     int off = snprintfcat(css, 0, sizeof(css),
         "font-size: %d; font-scale-x: %f; font-skew-x: %f; -paint-flags: %d;"
-        " font-weight: %d; font-style: %s; -minikin-bidi: %d;",
+        " font-weight: %d; font-style: %s; -minikin-bidi: %d; letter-spacing: %f;",
         (int)paint->getTextSize(),
         paint->getTextScaleX(),
         paint->getTextSkewX(),
         MinikinFontSkia::packPaintFlags(paint),
         style.getWeight() * 100,
         style.getItalic() ? "italic" : "normal",
-        bidiFlags);
+        bidiFlags,
+        paint->getLetterSpacing());
     SkString langString = paint->getPaintOptionsAndroid().getLanguage().getTag();
     off = snprintfcat(css, off, sizeof(css), " lang: %s;", langString.c_str());
     SkPaintOptionsAndroid::FontVariant var = paint->getPaintOptionsAndroid().getFontVariant();
     const char* varstr = var == SkPaintOptionsAndroid::kElegant_Variant ? "elegant" : "compact";
     off = snprintfcat(css, off, sizeof(css), " -minikin-variant: %s;", varstr);
-    return std::string(css);
+    layout->doLayout(buf, start, count, bufSize, std::string(css));
 }
 
 float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) {
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index 0562c3b1..647cbd8 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -45,8 +45,8 @@
 
 class MinikinUtils {
 public:
-    static std::string setLayoutProperties(Layout* layout, const Paint* paint, int bidiFlags,
-            TypefaceImpl* typeface);
+    static void doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
+            const uint16_t* buf, size_t start, size_t count, size_t bufSize);
 
     static float xOffsetForTextAlign(Paint* paint, const Layout& layout);
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index c06f0d2..a1f09bd 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -423,6 +423,16 @@
         GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(skewX);
     }
 
+    static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getLetterSpacing();
+    }
+
+    static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setLetterSpacing(letterSpacing);
+    }
+
     static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) {
         const int kElegantTop = 2500;
         const int kElegantBottom = -1000;
@@ -525,8 +535,7 @@
 
         Layout layout;
         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-        layout.doLayout(textArray, index, count, textLength, css);
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, index, count, textLength);
         result = layout.getAdvance();
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
@@ -553,8 +562,7 @@
 
         Layout layout;
         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-        layout.doLayout(textArray, start, count, textLength, css);
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, start, count, textLength);
         width = layout.getAdvance();
 
         env->ReleaseStringChars(text, textArray);
@@ -576,8 +584,7 @@
 
         Layout layout;
         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-        layout.doLayout(textArray, 0, textLength, textLength, css);
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength);
         width = layout.getAdvance();
 
         env->ReleaseStringChars(text, textArray);
@@ -606,8 +613,7 @@
         jfloat* widthsArray = autoWidths.ptr();
 
         Layout layout;
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-        layout.doLayout(text, 0, count, count, css);
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
         layout.getAdvances(widthsArray);
 
         return count;
@@ -660,8 +666,7 @@
         int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
 
         Layout layout;
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-        layout.doLayout(text, start, count, contextCount, css);
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
         layout.getAdvances(advancesArray);
         totalAdvance = layout.getAdvance();
 
@@ -760,8 +765,7 @@
     static void getTextPath(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar* text,
             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
         Layout layout;
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-        layout.doLayout(text, 0, count, count, css);
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
         size_t nGlyphs = layout.nGlyphs();
         uint16_t* glyphs = new uint16_t[nGlyphs];
         SkPoint* pos = new SkPoint[nGlyphs];
@@ -823,8 +827,7 @@
         float measured = 0;
 
         Layout layout;
-        std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
-        layout.doLayout(text, 0, count, count, css);
+        MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
         float* advances = new float[count];
         layout.getAdvances(advances);
         const bool forwardScan = (textBufferDirection == Paint::kForward_TextBufferDirection);
@@ -904,8 +907,7 @@
         SkIRect ir;
 
         Layout layout;
-        std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
-        layout.doLayout(text, 0, count, count, css);
+        MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
         MinikinRect rect;
         layout.getBounds(&rect);
         r.fLeft = rect.mLeft;
@@ -988,6 +990,8 @@
     {"setTextScaleX","(F)V", (void*) PaintGlue::setTextScaleX},
     {"getTextSkewX","()F", (void*) PaintGlue::getTextSkewX},
     {"setTextSkewX","(F)V", (void*) PaintGlue::setTextSkewX},
+    {"native_getLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
+    {"native_setLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
     {"ascent","()F", (void*) PaintGlue::ascent},
     {"descent","()F", (void*) PaintGlue::descent},
     {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics},
diff --git a/core/jni/android/graphics/Paint.h b/core/jni/android/graphics/Paint.h
index 239b217..7235cc4 100644
--- a/core/jni/android/graphics/Paint.h
+++ b/core/jni/android/graphics/Paint.h
@@ -34,7 +34,16 @@
         return !(a == b);
     }
 
+    void setLetterSpacing(float letterSpacing) {
+        mLetterSpacing = letterSpacing;
+    }
+
+    float getLetterSpacing() const {
+        return mLetterSpacing;
+    }
+
 private:
+    float mLetterSpacing;
 };
 
 }  // namespace android
diff --git a/core/jni/android/graphics/PaintImpl.cpp b/core/jni/android/graphics/PaintImpl.cpp
index 6baae76..ff2bbc5 100644
--- a/core/jni/android/graphics/PaintImpl.cpp
+++ b/core/jni/android/graphics/PaintImpl.cpp
@@ -22,10 +22,12 @@
 
 namespace android {
 
-Paint::Paint() : SkPaint() {
+Paint::Paint() : SkPaint(),
+        mLetterSpacing(0) {
 }
 
-Paint::Paint(const Paint& paint) : SkPaint(paint) {
+Paint::Paint(const Paint& paint) : SkPaint(paint),
+        mLetterSpacing(0) {
 }
 
 Paint::~Paint() {
@@ -33,11 +35,13 @@
 
 Paint& Paint::operator=(const Paint& other) {
     SkPaint::operator=(other);
+    mLetterSpacing = other.mLetterSpacing;
     return *this;
 }
 
 bool operator==(const Paint& a, const Paint& b) {
-    return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b);
+    return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b)
+            && a.mLetterSpacing == b.mLetterSpacing;
 }
 
 }
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index c71f226..fbb243a 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -50,15 +50,20 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle)
+static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
 {
     SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
     SkSafeUnref(shader);
+    SkShader* shaderWithLM = reinterpret_cast<SkShader*>(shaderWithLMHandle);
+    SkSafeUnref(shaderWithLM);
 }
 
 static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle,
-        jlong matrixHandle)
+        jlong oldLocalMatrixShaderHandle, jlong matrixHandle)
 {
+    // The old shader with local matrix is no longer needed, so unref it.
+    SkSafeUnref(reinterpret_cast<SkShader*>(oldLocalMatrixShaderHandle));
+
     SkShader* shader       = reinterpret_cast<SkShader*>(shaderHandle);
     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     if (shader) {
@@ -66,7 +71,6 @@
             matrix = &SkMatrix::I();
         }
         SkShader* newShader = SkShader::CreateLocalMatrixShader(shader, *matrix);
-        shader->unref();
         shader = newShader;
     }
     return reinterpret_cast<jlong>(shader);
@@ -239,8 +243,8 @@
 };
 
 static JNINativeMethod gShaderMethods[] = {
-    { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
-    { "nativeSetLocalMatrix",    "(JJ)J",   (void*)Shader_setLocalMatrix    }
+    { "nativeDestructor",        "(JJ)V",    (void*)Shader_destructor        },
+    { "nativeSetLocalMatrix",    "(JJJ)J",   (void*)Shader_setLocalMatrix    }
 };
 
 static JNINativeMethod gBitmapShaderMethods[] = {
diff --git a/core/jni/android/graphics/SkiaCanvas.cpp b/core/jni/android/graphics/SkiaCanvas.cpp
index f87033b..61ad398 100644
--- a/core/jni/android/graphics/SkiaCanvas.cpp
+++ b/core/jni/android/graphics/SkiaCanvas.cpp
@@ -34,7 +34,6 @@
 #include "MinikinSkia.h"
 #include "MinikinUtils.h"
 
-#include "Paint.h"
 #include "TypefaceImpl.h"
 
 #include "unicode/ubidi.h"
@@ -69,7 +68,7 @@
     virtual void restoreToCount(int saveCount);
 
     virtual int saveLayer(float left, float top, float right, float bottom,
-                const Paint* paint, SkCanvas::SaveFlags flags);
+                const SkPaint* paint, SkCanvas::SaveFlags flags);
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
             int alpha, SkCanvas::SaveFlags flags);
 
@@ -88,42 +87,46 @@
     virtual bool clipPath(const SkPath* path, SkRegion::Op op);
     virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
 
+    virtual SkDrawFilter* getDrawFilter();
     virtual void setDrawFilter(SkDrawFilter* drawFilter);
 
     virtual void drawColor(int color, SkXfermode::Mode mode);
-    virtual void drawPaint(const Paint& paint);
+    virtual void drawPaint(const SkPaint& paint);
 
-    virtual void drawPoint(float x, float y, const Paint& paint);
-    virtual void drawPoints(const float* points, int count, const Paint& paint);
+    virtual void drawPoint(float x, float y, const SkPaint& paint);
+    virtual void drawPoints(const float* points, int count, const SkPaint& paint);
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
-            const Paint& paint);
-    virtual void drawLines(const float* points, int count, const Paint& paint);
-    virtual void drawRect(float left, float top, float right, float bottom, const Paint& paint);
+            const SkPaint& paint);
+    virtual void drawLines(const float* points, int count, const SkPaint& paint);
+    virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint);
     virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const Paint& paint);
-    virtual void drawCircle(float x, float y, float radius, const Paint& paint);
-    virtual void drawOval(float left, float top, float right, float bottom, const Paint& paint);
+            float rx, float ry, const SkPaint& paint);
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint);
+    virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint);
     virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const Paint& paint);
-    virtual void drawPath(const SkPath& path, const Paint& paint);
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint);
+    virtual void drawPath(const SkPath& path, const SkPaint& paint);
     virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
             const float* verts, const float* tex, const int* colors,
-            const uint16_t* indices, int indexCount, const Paint& paint);
+            const uint16_t* indices, int indexCount, const SkPaint& paint);
 
-    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const Paint* paint);
-    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const Paint* paint);
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint);
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint);
     virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const Paint* paint);
+            float dstRight, float dstBottom, const SkPaint* paint);
     virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const Paint* paint);
+            const float* vertices, const int* colors, const SkPaint* paint);
 
-    virtual void drawText(const uint16_t* text, int start, int count, int contextCount,
-            float x, float y, int bidiFlags, const Paint& paint, TypefaceImpl* typeface);
+    virtual void drawText(const uint16_t* text, const float* positions, int count,
+            const SkPaint& paint, float x, float y,
+            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom);
     virtual void drawPosText(const uint16_t* text, const float* positions, int count,
-            int posCount, const Paint& paint);
+            int posCount, const SkPaint& paint);
     virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-            float hOffset, float vOffset, const Paint& paint);
+            float hOffset, float vOffset, const SkPaint& paint);
+
+    virtual bool drawTextAbsolutePos() const { return true; }
 
 private:
     struct SaveRec {
@@ -135,9 +138,9 @@
     void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount);
     void applyClips(const SkTArray<SkClipStack::Element>& clips);
 
-    void drawPoints(const float* points, int count, const Paint& paint,
+    void drawPoints(const float* points, int count, const SkPaint& paint,
                     SkCanvas::PointMode mode);
-    void drawTextDecorations(float x, float y, float length, const Paint& paint);
+    void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
 
     SkAutoTUnref<SkCanvas> mCanvas;
     SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
@@ -285,7 +288,7 @@
 }
 
 int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
-            const Paint* paint, SkCanvas::SaveFlags flags) {
+            const SkPaint* paint, SkCanvas::SaveFlags flags) {
     SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
     int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag);
     recordPartialSave(flags);
@@ -455,6 +458,10 @@
 // Canvas state operations: Filters
 // ----------------------------------------------------------------------------
 
+SkDrawFilter* SkiaCanvas::getDrawFilter() {
+    return mCanvas->getDrawFilter();
+}
+
 void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) {
     mCanvas->setDrawFilter(drawFilter);
 }
@@ -467,7 +474,7 @@
     mCanvas->drawColor(color, mode);
 }
 
-void SkiaCanvas::drawPaint(const Paint& paint) {
+void SkiaCanvas::drawPaint(const SkPaint& paint) {
     mCanvas->drawPaint(paint);
 }
 
@@ -475,7 +482,7 @@
 // Canvas draw operations: Geometry
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint,
+void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
                             SkCanvas::PointMode mode) {
     // convert the floats into SkPoints
     count >>= 1;    // now it is the number of points
@@ -489,57 +496,57 @@
 }
 
 
-void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
+void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
     mCanvas->drawPoint(x, y, paint);
 }
 
-void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
+void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
     this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
 }
 
 void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
-                          const Paint& paint) {
+                          const SkPaint& paint) {
     mCanvas->drawLine(startX, startY, stopX, stopY, paint);
 }
 
-void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
+void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
     this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
 }
 
 void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
-        const Paint& paint) {
+        const SkPaint& paint) {
     mCanvas->drawRectCoords(left, top, right, bottom, paint);
 
 }
 
 void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, const Paint& paint) {
+        float rx, float ry, const SkPaint& paint) {
     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
     mCanvas->drawRoundRect(rect, rx, ry, paint);
 }
 
-void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
+void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
     mCanvas->drawCircle(x, y, radius, paint);
 }
 
-void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) {
+void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
     SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
     mCanvas->drawOval(oval, paint);
 }
 
 void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
-        float startAngle, float sweepAngle, bool useCenter, const Paint& paint) {
+        float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
     SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
     mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
 }
 
-void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) {
+void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
     mCanvas->drawPath(path, paint);
 }
 
 void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
                               const float* verts, const float* texs, const int* colors,
-                              const uint16_t* indices, int indexCount, const Paint& paint) {
+                              const uint16_t* indices, int indexCount, const SkPaint& paint) {
 #ifndef SK_SCALAR_IS_FLOAT
     SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
 #endif
@@ -552,24 +559,24 @@
 // Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const Paint* paint) {
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
     mCanvas->drawBitmap(bitmap, left, top, paint);
 }
 
-void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
     mCanvas->drawBitmapMatrix(bitmap, matrix, paint);
 }
 
 void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
                             float srcRight, float srcBottom, float dstLeft, float dstTop,
-                            float dstRight, float dstBottom, const Paint* paint) {
+                            float dstRight, float dstBottom, const SkPaint* paint) {
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
     mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint);
 }
 
 void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-        const float* vertices, const int* colors, const Paint* paint) {
+        const float* vertices, const int* colors, const SkPaint* paint) {
 
     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
     const int indexCount = meshWidth * meshHeight * 6;
@@ -651,7 +658,7 @@
 #endif
 
     // cons-up a shader for the bitmap
-    Paint tmpPaint;
+    SkPaint tmpPaint;
     if (paint) {
         tmpPaint = *paint;
     }
@@ -669,89 +676,21 @@
 // Canvas draw operations: Text
 // ----------------------------------------------------------------------------
 
-class DrawTextFunctor {
-public:
-    DrawTextFunctor(const Layout& layout, SkCanvas* canvas, float x, float y, Paint* paint,
-                uint16_t* glyphs, SkPoint* pos)
-            : layout(layout), canvas(canvas), x(x), y(y), paint(paint), glyphs(glyphs),
-                pos(pos) { }
+void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count,
+        const SkPaint& paint, float x, float y,
+        float boundsLeft, float boundsTop, float boundsRight, float boundsBottom) {
+    // Set align to left for drawing, as we don't want individual
+    // glyphs centered or right-aligned; the offset above takes
+    // care of all alignment.
+    SkPaint paintCopy(paint);
+    paintCopy.setTextAlign(SkPaint::kLeft_Align);
 
-    void operator()(size_t start, size_t end) {
-        for (size_t i = start; i < end; i++) {
-            glyphs[i] = layout.getGlyphId(i);
-            pos[i].fX = x + layout.getX(i);
-            pos[i].fY = y + layout.getY(i);
-        }
-        canvas->drawPosText(glyphs + start, (end - start) << 1, pos + start, *paint);
-    }
-private:
-    const Layout& layout;
-    SkCanvas* canvas;
-    float x;
-    float y;
-    Paint* paint;
-    uint16_t* glyphs;
-    SkPoint* pos;
-};
-
-void SkiaCanvas::drawText(const uint16_t* text, int start, int count, int contextCount,
-        float x, float y, int bidiFlags, const Paint& paint, TypefaceImpl* typeface) {
-    Layout layout;
-    std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
-    layout.doLayout(text, start, count, contextCount, css);
-
-    size_t nGlyphs = layout.nGlyphs();
-    uint16_t* glyphs = new uint16_t[nGlyphs];
-    SkPoint* pos = new SkPoint[nGlyphs];
-
-    Paint paintCopy(paint);
-    x += MinikinUtils::xOffsetForTextAlign(&paintCopy, layout);
-    paintCopy.setTextAlign(Paint::kLeft_Align);
-    paintCopy.setTextEncoding(Paint::kGlyphID_TextEncoding);
-
-    DrawTextFunctor f(layout, mCanvas, x, y, &paintCopy, glyphs, pos);
-    MinikinUtils::forFontRun(layout, &paintCopy, f);
-    drawTextDecorations(x, y, layout.getAdvance(), paintCopy);
-
-    delete[] glyphs;
-    delete[] pos;
-}
-
-// Same values used by Skia
-#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
-#define kStdUnderline_Offset    (1.0f / 9.0f)
-#define kStdUnderline_Thickness (1.0f / 18.0f)
-
-void SkiaCanvas::drawTextDecorations(float x, float y, float length, const Paint& paint) {
-    uint32_t flags;
-    SkDrawFilter* drawFilter = mCanvas->getDrawFilter();
-    if (drawFilter) {
-        Paint paintCopy(paint);
-        drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
-        flags = paintCopy.getFlags();
-    } else {
-        flags = paint.getFlags();
-    }
-    if (flags & (Paint::kUnderlineText_Flag | Paint::kStrikeThruText_Flag)) {
-        SkScalar left = x;
-        SkScalar right = x + length;
-        float textSize = paint.getTextSize();
-        float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
-        if (flags & Paint::kUnderlineText_Flag) {
-            SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
-            SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
-            mCanvas->drawRectCoords(left, top, right, bottom, paint);
-        }
-        if (flags & Paint::kStrikeThruText_Flag) {
-            SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
-            SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
-            mCanvas->drawRectCoords(left, top, right, bottom, paint);
-        }
-    }
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
 }
 
 void SkiaCanvas::drawPosText(const uint16_t* text, const float* positions, int count, int posCount,
-        const Paint& paint) {
+        const SkPaint& paint) {
     SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
     int indx;
     for (indx = 0; indx < posCount; indx++) {
@@ -759,15 +698,15 @@
         posPtr[indx].fY = positions[(indx << 1) + 1];
     }
 
-    Paint paintCopy(paint);
-    paintCopy.setTextEncoding(Paint::kUTF16_TextEncoding);
+    SkPaint paintCopy(paint);
+    paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding);
     mCanvas->drawPosText(text, count, posPtr, paintCopy);
 
     delete[] posPtr;
 }
 
 void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-        float hOffset, float vOffset, const Paint& paint) {
+        float hOffset, float vOffset, const SkPaint& paint) {
     mCanvas->drawTextOnPathHV(glyphs, count, path, hOffset, vOffset, paint);
 }
 
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
deleted file mode 100644
index d58c692..0000000
--- a/core/jni/android/graphics/TextLayout.h
+++ /dev/null
@@ -1,82 +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.
- */
-
-#include "jni.h"
-
-#include "SkCanvas.h"
-#include "SkPaint.h"
-#include "unicode/utypes.h"
-
-#include "TextLayoutCache.h"
-
-namespace android {
-
-#define UNICODE_NOT_A_CHAR              0xffff
-#define UNICODE_ZWSP                    0x200b
-#define UNICODE_FIRST_LOW_SURROGATE     0xdc00
-#define UNICODE_FIRST_HIGH_SURROGATE    0xd800
-#define UNICODE_FIRST_PRIVATE_USE       0xe000
-#define UNICODE_FIRST_RTL_CHAR          0x0590
-
-/*
- * Temporary buffer size
- */
-#define CHAR_BUFFER_SIZE 80
-
-/**
- * Turn on for using the Cache
- */
-#define USE_TEXT_LAYOUT_CACHE 1
-
-enum {
-    kBidi_LTR = 0,
-    kBidi_RTL = 1,
-    kBidi_Default_LTR = 2,
-    kBidi_Default_RTL = 3,
-    kBidi_Force_LTR = 4,
-    kBidi_Force_RTL = 5,
-
-    kBidi_Mask = 0x7
-};
-
-enum {
-    kDirection_LTR = 0,
-    kDirection_RTL = 1,
-
-    kDirection_Mask = 0x1
-};
-
-class TextLayout {
-public:
-
-    static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                   jint count, jint contextCount, jint dirFlags,
-                                   jfloat* resultAdvances, jfloat* resultTotalAdvance);
-
-    static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
-                            jint bidiFlags, jfloat x, jfloat y, SkPath* path);
-
-    static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
-                               int bidiFlags, jfloat hOffset, jfloat vOffset,
-                               SkPath* path, SkCanvas* canvas);
-
-private:
-    static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
-
-    static void handleText(SkPaint* paint, const jchar* text, jsize len,
-                           int bidiFlags, jfloat x, jfloat y, SkPath* path);
-};
-} // namespace android
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 377e71c..a9b01d0 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -19,6 +19,7 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include "Canvas.h"
+#include "SkDrawFilter.h"
 #include "SkGraphics.h"
 #include "SkPorterDuff.h"
 #include "Paint.h"
@@ -409,13 +410,109 @@
                                              vertA.ptr(), colorA.ptr(), paint);
 }
 
+class DrawTextFunctor {
+public:
+    DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
+                    const SkPaint& paint, float x, float y, MinikinRect& bounds)
+            : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint),
+              x(x), y(y), bounds(bounds) { }
+
+    void operator()(size_t start, size_t end) {
+        if (canvas->drawTextAbsolutePos()) {
+            for (size_t i = start; i < end; i++) {
+                glyphs[i] = layout.getGlyphId(i);
+                pos[2 * i] = x + layout.getX(i);
+                pos[2 * i + 1] = y + layout.getY(i);
+            }
+        } else {
+            for (size_t i = start; i < end; i++) {
+                glyphs[i] = layout.getGlyphId(i);
+                pos[2 * i] = layout.getX(i);
+                pos[2 * i + 1] = layout.getY(i);
+            }
+        }
+
+        size_t glyphCount = end - start;
+        canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, paint, x, y,
+                         bounds.mLeft , bounds.mTop , bounds.mRight , bounds.mBottom);
+    }
+private:
+    const Layout& layout;
+    Canvas* canvas;
+    uint16_t* glyphs;
+    float* pos;
+    const SkPaint& paint;
+    float x;
+    float y;
+    MinikinRect& bounds;
+};
+
+// Same values used by Skia
+#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
+#define kStdUnderline_Offset    (1.0f / 9.0f)
+#define kStdUnderline_Thickness (1.0f / 18.0f)
+
+void drawTextDecorations(Canvas* canvas, float x, float y, float length, const SkPaint& paint) {
+    uint32_t flags;
+    SkDrawFilter* drawFilter = canvas->getDrawFilter();
+    if (drawFilter) {
+        SkPaint paintCopy(paint);
+        drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
+        flags = paintCopy.getFlags();
+    } else {
+        flags = paint.getFlags();
+    }
+    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
+        SkScalar left = x;
+        SkScalar right = x + length;
+        float textSize = paint.getTextSize();
+        float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
+        if (flags & SkPaint::kUnderlineText_Flag) {
+            SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
+            SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
+            canvas->drawRect(left, top, right, bottom, paint);
+        }
+        if (flags & SkPaint::kStrikeThruText_Flag) {
+            SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
+            SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
+            canvas->drawRect(left, top, right, bottom, paint);
+        }
+    }
+}
+
+void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int contextCount,
+             float x, float y, int bidiFlags, const Paint& origPaint, TypefaceImpl* typeface) {
+    // minikin may modify the original paint
+    Paint paint(origPaint);
+
+    Layout layout;
+    MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
+
+    size_t nGlyphs = layout.nGlyphs();
+    uint16_t* glyphs = new uint16_t[nGlyphs];
+    float* pos = new float[nGlyphs * 2];
+
+    x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
+
+    MinikinRect bounds;
+    layout.getBounds(&bounds);
+
+    DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds);
+    MinikinUtils::forFontRun(layout, &paint, f);
+
+    drawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
+
+    delete[] glyphs;
+    delete[] pos;
+}
+
 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
                           jlong paintHandle, jlong typefaceHandle) {
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
     jchar* jchars = env->GetCharArrayElements(text, NULL);
-    get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
+    drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y,
                                        bidiFlags, *paint, typeface);
     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
 }
@@ -427,7 +524,7 @@
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
     const int count = end - start;
     const jchar* jchars = env->GetStringChars(text, NULL);
-    get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
+    drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y,
                                        bidiFlags, *paint, typeface);
     env->ReleaseStringChars(text, jchars);
 }
@@ -440,7 +537,7 @@
 
     const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
     jchar* jchars = env->GetCharArrayElements(text, NULL);
-    get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
+    drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count,
                                        contextCount, x, y, bidiFlags, *paint, typeface);
     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
 }
@@ -456,7 +553,7 @@
     jint count = end - start;
     jint contextCount = contextEnd - contextStart;
     const jchar* jchars = env->GetStringChars(text, NULL);
-    get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
+    drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count,
                                        contextCount, x, y, bidiFlags, *paint, typeface);
     env->ReleaseStringChars(text, jchars);
 }
@@ -527,8 +624,7 @@
                            const Paint& paint, TypefaceImpl* typeface) {
     Paint paintCopy(paint);
     Layout layout;
-    std::string css = MinikinUtils::setLayoutProperties(&layout, &paintCopy, bidiFlags, typeface);
-    layout.doLayout(text, 0, count, count, css);
+    MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
     hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
 
     // Set align to left for drawing, as we don't want individual
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 3a3328f..eaadfb2 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -1173,8 +1173,8 @@
             calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
         }
 
-        BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1,
-                TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer);
+        BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count,
+                calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer);
 
         if (!singleIlluminant) {
             camera_metadata_entry entry2 =
@@ -1188,8 +1188,8 @@
                 calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
             }
 
-            BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1,
-                    TIFF_IFD_0),  env, TAG_CAMERACALIBRATION2, writer);
+            BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count,
+                    calibrationTransform1, TIFF_IFD_0),  env, TAG_CAMERACALIBRATION2, writer);
         }
     }
 
@@ -1294,6 +1294,21 @@
     }
 
     {
+        // Setup sensor noise model
+        camera_metadata_entry entry =
+            results.find(ANDROID_SENSOR_NOISE_PROFILE);
+
+        if (entry.count > 0) {
+            BAIL_IF_INVALID(writer->addEntry(TAG_NOISEPROFILE, entry.count,
+                    entry.data.d, TIFF_IFD_0), env,
+                    TAG_NOISEPROFILE, writer);
+        } else {
+            ALOGW("%s: No noise profile found in result metadata.  Image quality may be reduced.",
+                    __FUNCTION__);
+        }
+    }
+
+    {
         // Setup opcode List 2
         camera_metadata_entry entry1 =
                 characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index d2f5b5d..697cdc6 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -587,7 +587,7 @@
 
     int32_t transform = 0;
 
-    if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != OK) {
+    if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != NO_ERROR) {
         ALOGE("%s: Invalid rotation transform %s (%d)", __FUNCTION__, strerror(-err),
                 err);
         return err;
@@ -595,7 +595,7 @@
 
     ALOGV("%s: Setting buffer sticky transform to %d", __FUNCTION__, transform);
 
-    if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != OK) {
+    if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != NO_ERROR) {
         ALOGE("%s: Unable to configure surface transform, error %s (%d)", __FUNCTION__,
                 strerror(-err), err);
         return err;
@@ -604,6 +604,26 @@
     return NO_ERROR;
 }
 
+static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz, jobject surface,
+        jlong timestamp) {
+    ALOGV("nativeSetNextTimestamp");
+    sp<ANativeWindow> anw;
+    if ((anw = getNativeWindow(env, surface)) == NULL) {
+        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err = NO_ERROR;
+
+    if ((err = native_window_set_buffers_timestamp(anw.get(), static_cast<int64_t>(timestamp))) !=
+            NO_ERROR) {
+        ALOGE("%s: Unable to set surface timestamp, error %s (%d)", __FUNCTION__, strerror(-err),
+                err);
+        return err;
+    }
+    return NO_ERROR;
+}
+
 } // extern "C"
 
 static JNINativeMethod gCameraDeviceMethods[] = {
@@ -634,6 +654,9 @@
     { "nativeSetSurfaceOrientation",
     "(Landroid/view/Surface;II)I",
     (void *)LegacyCameraDevice_nativeSetSurfaceOrientation },
+    { "nativeSetNextTimestamp",
+    "(Landroid/view/Surface;J)I",
+    (void *)LegacyCameraDevice_nativeSetNextTimestamp },
 };
 
 // Get all the required offsets in java class and register native functions
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 7e2448e..e0431a7 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -290,7 +290,7 @@
     case MODE_STREAM:
 
         status = lpTrack->set(
-                AUDIO_STREAM_DEFAULT,// stream type
+                AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
                 sampleRateInHertz,
                 format,// word length, PCM
                 nativeChannelMask,
@@ -301,7 +301,7 @@
                 0,// shared mem
                 true,// thread can call Java
                 sessionId,// audio session ID
-                AudioTrack::TRANSFER_DEFAULT, // default transfer mode
+                AudioTrack::TRANSFER_SYNC,
                 NULL,                         // default offloadInfo
                 -1, -1,                       // default uid, pid values
                 paa);
@@ -316,7 +316,7 @@
         }
 
         status = lpTrack->set(
-                AUDIO_STREAM_DEFAULT,// stream type
+                AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
                 sampleRateInHertz,
                 format,// word length, PCM
                 nativeChannelMask,
@@ -327,7 +327,7 @@
                 lpJniStorage->mMemBase,// shared mem
                 true,// thread can call Java
                 sessionId,// audio session ID
-                AudioTrack::TRANSFER_DEFAULT, // default transfer mode
+                AudioTrack::TRANSFER_SHARED,
                 NULL,                         // default offloadInfo
                 -1, -1,                       // default uid, pid values
                 paa);
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 50f6c73..44863cc 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -187,6 +187,45 @@
     }
 }
 
+static void android_os_Parcel_writeBlob(JNIEnv* env, jclass clazz, jlong nativePtr, jobject data,
+                                        jint offset, jint length) {
+    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+    if (parcel == NULL) {
+        return;
+    }
+
+    if (data == NULL) {
+        const status_t err = parcel->writeInt32(-1);
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+        return;
+    }
+
+    const status_t err = parcel->writeInt32(length);
+    if (err != NO_ERROR) {
+        signalExceptionForError(env, clazz, err);
+        return;
+    }
+
+    android::Parcel::WritableBlob blob;
+    android::status_t err2 = parcel->writeBlob(length, &blob);
+    if (err2 != NO_ERROR) {
+        signalExceptionForError(env, clazz, err2);
+        return;
+    }
+
+    jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
+    if (ar == NULL) {
+        memset(blob.data(), 0, length);
+    } else {
+        memcpy(blob.data(), ar + offset, length);
+        env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
+    }
+
+    blob.release();
+}
+
 static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
     Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
     const status_t err = parcel->writeInt32(val);
@@ -297,6 +336,36 @@
     return ret;
 }
 
+static jbyteArray android_os_Parcel_readBlob(JNIEnv* env, jclass clazz, jlong nativePtr)
+{
+    jbyteArray ret = NULL;
+
+    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+    if (parcel != NULL) {
+        int32_t len = parcel->readInt32();
+        if (len >= 0) {
+            android::Parcel::ReadableBlob blob;
+            android::status_t err = parcel->readBlob(len, &blob);
+            if (err != NO_ERROR) {
+                signalExceptionForError(env, clazz, err);
+                return NULL;
+            }
+
+            ret = env->NewByteArray(len);
+            if (ret != NULL) {
+                jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
+                if (a2) {
+                    memcpy(a2, blob.data(), len);
+                    env->ReleasePrimitiveArrayCritical(ret, a2, 0);
+                }
+            }
+            blob.release();
+        }
+    }
+
+    return ret;
+}
+
 static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr)
 {
     Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
@@ -634,6 +703,7 @@
     {"nativeRestoreAllowFds",     "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
 
     {"nativeWriteByteArray",      "(J[BII)V", (void*)android_os_Parcel_writeNative},
+    {"nativeWriteBlob",           "(J[BII)V", (void*)android_os_Parcel_writeBlob},
     {"nativeWriteInt",            "(JI)V", (void*)android_os_Parcel_writeInt},
     {"nativeWriteLong",           "(JJ)V", (void*)android_os_Parcel_writeLong},
     {"nativeWriteFloat",          "(JF)V", (void*)android_os_Parcel_writeFloat},
@@ -643,6 +713,7 @@
     {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
 
     {"nativeCreateByteArray",     "(J)[B", (void*)android_os_Parcel_createByteArray},
+    {"nativeReadBlob",            "(J)[B", (void*)android_os_Parcel_readBlob},
     {"nativeReadInt",             "(J)I", (void*)android_os_Parcel_readInt},
     {"nativeReadLong",            "(J)J", (void*)android_os_Parcel_readLong},
     {"nativeReadFloat",           "(J)F", (void*)android_os_Parcel_readFloat},
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
deleted file mode 100644
index 28a8a5d..0000000
--- a/core/jni/android_text_format_Time.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-#define LOG_TAG "Log_println"
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <assert.h>
-
-#include "jni.h"
-#include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "ScopedStringChars.h"
-#include "TimeUtils.h"
-#include <nativehelper/JNIHelp.h>
-#include <cutils/tztime.h>
-
-namespace android {
-
-static jfieldID g_allDayField = 0;
-static jfieldID g_secField = 0;
-static jfieldID g_minField = 0;
-static jfieldID g_hourField = 0;
-static jfieldID g_mdayField = 0;
-static jfieldID g_monField = 0;
-static jfieldID g_yearField = 0;
-static jfieldID g_wdayField = 0;
-static jfieldID g_ydayField = 0;
-static jfieldID g_isdstField = 0;
-static jfieldID g_gmtoffField = 0;
-static jfieldID g_timezoneField = 0;
-
-static jfieldID g_shortMonthsField = 0;
-static jfieldID g_longMonthsField = 0;
-static jfieldID g_longStandaloneMonthsField = 0;
-static jfieldID g_shortWeekdaysField = 0;
-static jfieldID g_longWeekdaysField = 0;
-static jfieldID g_timeOnlyFormatField = 0;
-static jfieldID g_dateOnlyFormatField = 0;
-static jfieldID g_dateTimeFormatField = 0;
-static jfieldID g_amField = 0;
-static jfieldID g_pmField = 0;
-static jfieldID g_dateCommandField = 0;
-static jfieldID g_localeField = 0;
-
-static jclass g_timeClass = NULL;
-
-static inline bool java2time(JNIEnv* env, Time* t, jobject o)
-{
-    t->t.tm_sec = env->GetIntField(o, g_secField);
-    t->t.tm_min = env->GetIntField(o, g_minField);
-    t->t.tm_hour = env->GetIntField(o, g_hourField);
-    t->t.tm_mday = env->GetIntField(o, g_mdayField);
-    t->t.tm_mon = env->GetIntField(o, g_monField);
-    t->t.tm_year = (env->GetIntField(o, g_yearField))-1900;
-    t->t.tm_wday = env->GetIntField(o, g_wdayField);
-    t->t.tm_yday = env->GetIntField(o, g_ydayField);
-    t->t.tm_isdst = env->GetIntField(o, g_isdstField);
-    t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField);
-    bool allDay = env->GetBooleanField(o, g_allDayField);
-    if (allDay &&
-       ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
-        jniThrowException(env, "java/lang/IllegalArgumentException",
-                          "allDay is true but sec, min, hour are not 0.");
-        return false;
-    }
-    return true;
-}
-
-static inline void time2java(JNIEnv* env, jobject o, const Time &t)
-{
-    env->SetIntField(o, g_secField, t.t.tm_sec);
-    env->SetIntField(o, g_minField, t.t.tm_min);
-    env->SetIntField(o, g_hourField, t.t.tm_hour);
-    env->SetIntField(o, g_mdayField, t.t.tm_mday);
-    env->SetIntField(o, g_monField, t.t.tm_mon);
-    env->SetIntField(o, g_yearField, t.t.tm_year+1900);
-    env->SetIntField(o, g_wdayField, t.t.tm_wday);
-    env->SetIntField(o, g_ydayField, t.t.tm_yday);
-    env->SetIntField(o, g_isdstField, t.t.tm_isdst);
-    env->SetLongField(o, g_gmtoffField, t.t.tm_gmtoff);
-}
-
-#define ACQUIRE_TIMEZONE(This, t) \
-    jstring timezoneString_##This \
-            = (jstring) env->GetObjectField(This, g_timezoneField); \
-    t.timezone = env->GetStringUTFChars(timezoneString_##This, NULL);
-
-#define RELEASE_TIMEZONE(This, t) \
-    env->ReleaseStringUTFChars(timezoneString_##This, t.timezone);
-
-
-// ============================================================================
-
-static jlong android_text_format_Time_normalize(JNIEnv* env, jobject This,
-                                           jboolean ignoreDst)
-{
-    Time t;
-    if (!java2time(env, &t, This)) return 0L;
-    ACQUIRE_TIMEZONE(This, t)
-
-    int64_t result = t.toMillis(ignoreDst != 0);
-
-    time2java(env, This, t);
-    RELEASE_TIMEZONE(This, t)
-
-    return static_cast<jlong>(result);
-}
-
-static void android_text_format_Time_switchTimezone(JNIEnv* env, jobject This,
-                            jstring timezoneObject)
-{
-    Time t;
-    if (!java2time(env, &t, This)) return;
-    ACQUIRE_TIMEZONE(This, t)
-
-    const char* timezone = env->GetStringUTFChars(timezoneObject, NULL);
-
-    t.switchTimezone(timezone);
-
-    time2java(env, This, t);
-    env->ReleaseStringUTFChars(timezoneObject, timezone);
-    RELEASE_TIMEZONE(This, t)
-
-    // we do this here because there's no point in reallocating the string
-    env->SetObjectField(This, g_timezoneField, timezoneObject);
-}
-
-static jint android_text_format_Time_compare(JNIEnv* env, jobject clazz,
-                            jobject aObject, jobject bObject)
-{
-    Time a, b;
-
-    if (!java2time(env, &a, aObject)) return 0;
-    ACQUIRE_TIMEZONE(aObject, a)
-
-    if (!java2time(env, &b, bObject)) return 0;
-    ACQUIRE_TIMEZONE(bObject, b)
-
-    int result = Time::compare(a, b);
-
-    RELEASE_TIMEZONE(aObject, a)
-    RELEASE_TIMEZONE(bObject, b)
-
-    return static_cast<jint>(result);
-}
-
-static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This)
-{
-    Time t;
-    if (!java2time(env, &t, This)) return env->NewStringUTF("");
-    bool allDay = env->GetBooleanField(This, g_allDayField);
-    
-    if (!allDay) {
-        ACQUIRE_TIMEZONE(This, t)
-        bool inUtc = strcmp("UTC", t.timezone) == 0;
-        short buf[16];
-        t.format2445(buf, true);
-        RELEASE_TIMEZONE(This, t)
-        if (inUtc) {
-            // The letter 'Z' is appended to the end so allow for one
-            // more character in the buffer.
-            return env->NewString((jchar*)buf, 16);
-        } else {
-            return env->NewString((jchar*)buf, 15);
-        }
-    } else {
-        short buf[8];
-        t.format2445(buf, false);
-        return env->NewString((jchar*)buf, 8);
-    }
-}
-
-static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
-                            jstring formatObject)
-{
-    // We only teardown and setup our 'locale' struct and other state
-    // when the Java-side locale changed.  This is safe to do here
-    // without locking because we're always called from Java code
-    // synchronized on the class instance.
-    static jobject js_locale_previous = NULL;
-    static struct strftime_locale locale;
-    static jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7];
-    static jstring js_standalone_month[12];
-    static jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt;
-
-    Time t;
-    if (!java2time(env, &t, This)) return env->NewStringUTF("");
-
-    jclass timeClass = g_timeClass;
-    jobject js_locale = (jobject) env->GetStaticObjectField(timeClass, g_localeField);
-    if (js_locale_previous != js_locale) {
-        if (js_locale_previous != NULL) {
-            // Free the old one.
-            for (int i = 0; i < 12; i++) {
-                env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]);
-                env->ReleaseStringUTFChars(js_month[i], locale.month[i]);
-                env->ReleaseStringUTFChars(js_standalone_month[i], locale.standalone_month[i]);
-                env->DeleteGlobalRef(js_mon[i]);
-                env->DeleteGlobalRef(js_month[i]);
-                env->DeleteGlobalRef(js_standalone_month[i]);
-            }
-
-            for (int i = 0; i < 7; i++) {
-                env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]);
-                env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]);
-                env->DeleteGlobalRef(js_wday[i]);
-                env->DeleteGlobalRef(js_weekday[i]);
-            }
-
-            env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt);
-            env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt);
-            env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt);
-            env->ReleaseStringUTFChars(js_am, locale.am);
-            env->ReleaseStringUTFChars(js_pm, locale.pm);
-            env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt);
-            env->DeleteGlobalRef(js_X_fmt);
-            env->DeleteGlobalRef(js_x_fmt);
-            env->DeleteGlobalRef(js_c_fmt);
-            env->DeleteGlobalRef(js_am);
-            env->DeleteGlobalRef(js_pm);
-            env->DeleteGlobalRef(js_date_fmt);
-        }
-        js_locale_previous = js_locale;
-
-        jobjectArray ja;
-        ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField);
-        for (int i = 0; i < 12; i++) {
-            // Calendar.JANUARY == 0.
-            js_mon[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
-            locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL);
-        }
-
-        ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField);
-        for (int i = 0; i < 12; i++) {
-            // Calendar.JANUARY == 0.
-            js_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
-            locale.month[i] = env->GetStringUTFChars(js_month[i], NULL);
-        }
-
-        ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longStandaloneMonthsField);
-        for (int i = 0; i < 12; i++) {
-            // Calendar.JANUARY == 0.
-            js_standalone_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
-            locale.standalone_month[i] = env->GetStringUTFChars(js_standalone_month[i], NULL);
-        }
-
-        ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField);
-        for (int i = 0; i < 7; i++) {
-            // Calendar.SUNDAY == 1, and there's an empty string in element 0.
-            js_wday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i + 1));
-            locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL);
-        }
-
-        ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField);
-        for (int i = 0; i < 7; i++) {
-            // Calendar.SUNDAY == 1, and there's an empty string in element 0.
-            js_weekday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i + 1));
-            locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL);
-        }
-
-        js_X_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
-                                                       timeClass, g_timeOnlyFormatField));
-        locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL);
-
-        js_x_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
-                                                       timeClass, g_dateOnlyFormatField));
-        locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL);
-
-        js_c_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
-                                                       timeClass, g_dateTimeFormatField));
-        locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL);
-
-        js_am = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
-                                                    timeClass, g_amField));
-        locale.am = env->GetStringUTFChars(js_am, NULL);
-
-        js_pm = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
-                                                    timeClass, g_pmField));
-        locale.pm = env->GetStringUTFChars(js_pm, NULL);
-
-        js_date_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
-                                                          timeClass, g_dateCommandField));
-        locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL);
-    }
-
-    ACQUIRE_TIMEZONE(This, t)
-
-    const char* format = env->GetStringUTFChars(formatObject, NULL);
-
-    String8 r = t.format(format, &locale);
-
-    env->ReleaseStringUTFChars(formatObject, format);
-    RELEASE_TIMEZONE(This, t)
-
-    return env->NewStringUTF(r.string());
-}
-
-
-static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
-{
-    Time t;
-    if (!java2time(env, &t, This)) return env->NewStringUTF("");
-    ACQUIRE_TIMEZONE(This, t)
-
-    String8 r = t.toString();
-
-    RELEASE_TIMEZONE(This, t)
-
-    return env->NewStringUTF(r.string());
-}
-
-static void android_text_format_Time_setToNow(JNIEnv* env, jobject This)
-{
-    env->SetBooleanField(This, g_allDayField, JNI_FALSE);
-    Time t;
-    ACQUIRE_TIMEZONE(This, t)
-
-    t.setToNow();
-
-    time2java(env, This, t);
-    RELEASE_TIMEZONE(This, t)
-}
-
-static jlong android_text_format_Time_toMillis(JNIEnv* env, jobject This,
-                                        jboolean ignoreDst)
-{
-    Time t;
-    if (!java2time(env, &t, This)) return 0L;
-    ACQUIRE_TIMEZONE(This, t)
-
-    int64_t result = t.toMillis(ignoreDst != 0);
-
-    RELEASE_TIMEZONE(This, t)
-
-    return static_cast<jlong>(result);
-}
-
-static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis)
-{
-    env->SetBooleanField(This, g_allDayField, JNI_FALSE);
-    Time t;
-    ACQUIRE_TIMEZONE(This, t)
-
-    t.set(millis);
-
-    time2java(env, This, t);
-    RELEASE_TIMEZONE(This, t)
-}
-
-
-// ============================================================================
-// Just do this here because it's not worth recreating the strings
-
-static int get_char(JNIEnv* env, const ScopedStringChars& s, int spos, int mul,
-                    bool* thrown)
-{
-    jchar c = s[spos];
-    if (c >= '0' && c <= '9') {
-        return (c - '0') * mul;
-    } else {
-        if (!*thrown) {
-            jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                                 "Parse error at pos=%d", spos);
-            *thrown = true;
-        }
-        return 0;
-    }
-}
-
-static bool check_char(JNIEnv* env, const ScopedStringChars& s, int spos, jchar expected)
-{
-    jchar c = s[spos];
-    if (c != expected) {
-        jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                             "Unexpected character 0x%02x at pos=%d.  Expected %c.",
-                             c, spos, expected);
-        return false;
-    }
-    return true;
-}
-
-
-static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
-{
-    jsize len = env->GetStringLength(strObj);
-    if (len < 8) {
-        jniThrowException(env, "android/util/TimeFormatException",
-                          "String too short -- expected at least 8 characters.");
-        return JNI_FALSE;
-    }
-
-    jboolean inUtc = JNI_FALSE;
-
-    ScopedStringChars s(env, strObj);
-
-    // year
-    int n;
-    bool thrown = false;
-    n = get_char(env, s, 0, 1000, &thrown);
-    n += get_char(env, s, 1, 100, &thrown);
-    n += get_char(env, s, 2, 10, &thrown);
-    n += get_char(env, s, 3, 1, &thrown);
-    if (thrown) return JNI_FALSE;
-    env->SetIntField(This, g_yearField, n);
-
-    // month
-    n = get_char(env, s, 4, 10, &thrown);
-    n += get_char(env, s, 5, 1, &thrown);
-    n--;
-    if (thrown) return JNI_FALSE;
-    env->SetIntField(This, g_monField, n);
-
-    // day of month
-    n = get_char(env, s, 6, 10, &thrown);
-    n += get_char(env, s, 7, 1, &thrown);
-    if (thrown) return JNI_FALSE;
-    env->SetIntField(This, g_mdayField, n);
-
-    if (len > 8) {
-        // T
-        if (!check_char(env, s, 8, 'T')) return JNI_FALSE;
-        env->SetBooleanField(This, g_allDayField, JNI_FALSE);
-
-        // hour
-        n = get_char(env, s, 9, 10, &thrown);
-        n += get_char(env, s, 10, 1, &thrown);
-        if (thrown) return JNI_FALSE;
-        env->SetIntField(This, g_hourField, n);
-
-        // min
-        n = get_char(env, s, 11, 10, &thrown);
-        n += get_char(env, s, 12, 1, &thrown);
-        if (thrown) return JNI_FALSE;
-        env->SetIntField(This, g_minField, n);
-
-        // sec
-        n = get_char(env, s, 13, 10, &thrown);
-        n += get_char(env, s, 14, 1, &thrown);
-        if (thrown) return JNI_FALSE;
-        env->SetIntField(This, g_secField, n);
-
-        if (len > 15) {
-            // Z
-            if (!check_char(env, s, 15, 'Z')) return JNI_FALSE;
-            inUtc = JNI_TRUE;
-        }
-    } else {
-        env->SetBooleanField(This, g_allDayField, JNI_TRUE);
-        env->SetIntField(This, g_hourField, 0);
-        env->SetIntField(This, g_minField, 0);
-        env->SetIntField(This, g_secField, 0);
-    }
-
-    env->SetIntField(This, g_wdayField, 0);
-    env->SetIntField(This, g_ydayField, 0);
-    env->SetIntField(This, g_isdstField, -1);
-    env->SetLongField(This, g_gmtoffField, 0);
-
-    return inUtc;
-}
-
-static jboolean android_text_format_Time_parse3339(JNIEnv* env, 
-                                           jobject This, 
-                                           jstring strObj)
-{
-    jsize len = env->GetStringLength(strObj);
-    if (len < 10) {
-        jniThrowException(env, "android/util/TimeFormatException",
-                          "String too short --- expected at least 10 characters.");
-        return JNI_FALSE;
-    }
-
-    jboolean inUtc = JNI_FALSE;
-
-    ScopedStringChars s(env, strObj);
-
-    // year
-    int n;
-    bool thrown = false;
-    n = get_char(env, s, 0, 1000, &thrown);    
-    n += get_char(env, s, 1, 100, &thrown);
-    n += get_char(env, s, 2, 10, &thrown);
-    n += get_char(env, s, 3, 1, &thrown);
-    if (thrown) return JNI_FALSE;
-    env->SetIntField(This, g_yearField, n);
-    
-    // -
-    if (!check_char(env, s, 4, '-')) return JNI_FALSE;
-    
-    // month
-    n = get_char(env, s, 5, 10, &thrown);
-    n += get_char(env, s, 6, 1, &thrown);
-    --n;
-    if (thrown) return JNI_FALSE;
-    env->SetIntField(This, g_monField, n);
-
-    // -
-    if (!check_char(env, s, 7, '-')) return JNI_FALSE;
-
-    // day
-    n = get_char(env, s, 8, 10, &thrown);
-    n += get_char(env, s, 9, 1, &thrown);
-    if (thrown) return JNI_FALSE;
-    env->SetIntField(This, g_mdayField, n);
-
-    if (len >= 19) {
-        // T
-        if (!check_char(env, s, 10, 'T')) return JNI_FALSE;
-
-        env->SetBooleanField(This, g_allDayField, JNI_FALSE);
-        // hour
-        n = get_char(env, s, 11, 10, &thrown);
-        n += get_char(env, s, 12, 1, &thrown);
-        if (thrown) return JNI_FALSE;
-        int hour = n;
-        // env->SetIntField(This, g_hourField, n);
-
-        // :
-        if (!check_char(env, s, 13, ':')) return JNI_FALSE;
-
-        // minute
-        n = get_char(env, s, 14, 10, &thrown);
-        n += get_char(env, s, 15, 1, &thrown);
-        if (thrown) return JNI_FALSE;
-        int minute = n;
-        // env->SetIntField(This, g_minField, n);
-
-        // :
-        if (!check_char(env, s, 16, ':')) return JNI_FALSE;
-
-        // second
-        n = get_char(env, s, 17, 10, &thrown);
-        n += get_char(env, s, 18, 1, &thrown);
-        if (thrown) return JNI_FALSE;
-        env->SetIntField(This, g_secField, n);
-
-        // skip the '.XYZ' -- we don't care about subsecond precision.
-        int tz_index = 19;
-        if (tz_index < len && s[tz_index] == '.') {
-            do {
-                tz_index++;
-            } while (tz_index < len
-                && s[tz_index] >= '0'
-                && s[tz_index] <= '9');
-        }
-
-        int offset = 0;
-        if (len > tz_index) {
-            char c = s[tz_index];
-
-            // NOTE: the offset is meant to be subtracted to get from local time
-            // to UTC.  we therefore use 1 for '-' and -1 for '+'.
-            switch (c) {
-            case 'Z':
-                // Zulu time -- UTC
-                offset = 0;
-                break;
-            case '-': 
-                offset = 1;
-                break;
-            case '+': 
-                offset = -1;
-                break;
-            default:
-                jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                                     "Unexpected character 0x%02x at position %d.  Expected + or -",
-                                     c, tz_index);
-                return JNI_FALSE;
-            }
-            inUtc = JNI_TRUE;
-
-            if (offset != 0) {
-                if (len < tz_index + 6) {
-                    jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                                         "Unexpected length; should be %d characters",
-                                         tz_index + 6);
-                    return JNI_FALSE;
-                }
-
-                // hour
-                n = get_char(env, s, tz_index + 1, 10, &thrown);
-                n += get_char(env, s, tz_index + 2, 1, &thrown);
-                if (thrown) return JNI_FALSE;
-                n *= offset;
-                hour += n;
-
-                // :
-                if (!check_char(env, s, tz_index + 3, ':')) return JNI_FALSE;
-            
-                // minute
-                n = get_char(env, s, tz_index + 4, 10, &thrown);
-                n += get_char(env, s, tz_index + 5, 1, &thrown);
-                if (thrown) return JNI_FALSE;
-                n *= offset;
-                minute += n;
-            }
-        }
-        env->SetIntField(This, g_hourField, hour);
-        env->SetIntField(This, g_minField, minute);
-
-        if (offset != 0) {
-            // we need to normalize after applying the hour and minute offsets
-            android_text_format_Time_normalize(env, This, false /* use isdst */);
-            // The timezone is set to UTC in the calling Java code.
-        }
-    } else {
-        env->SetBooleanField(This, g_allDayField, JNI_TRUE);
-        env->SetIntField(This, g_hourField, 0);
-        env->SetIntField(This, g_minField, 0);
-        env->SetIntField(This, g_secField, 0);
-    }
-
-    env->SetIntField(This, g_wdayField, 0);
-    env->SetIntField(This, g_ydayField, 0);
-    env->SetIntField(This, g_isdstField, -1);
-    env->SetLongField(This, g_gmtoffField, 0);
-
-    return inUtc;
-}
-
-// ============================================================================
-/*
- * JNI registration.
- */
-static JNINativeMethod gMethods[] = {
-    /* name, signature, funcPtr */
-    { "normalize",               "(Z)J",                                        (void*)android_text_format_Time_normalize },
-    { "switchTimezone",          "(Ljava/lang/String;)V",                       (void*)android_text_format_Time_switchTimezone },
-    { "nativeCompare",           "(Landroid/text/format/Time;Landroid/text/format/Time;)I",     (void*)android_text_format_Time_compare },
-    { "format1",                 "(Ljava/lang/String;)Ljava/lang/String;",      (void*)android_text_format_Time_format },
-    { "format2445",              "()Ljava/lang/String;",                        (void*)android_text_format_Time_format2445 },
-    { "toString",                "()Ljava/lang/String;",                        (void*)android_text_format_Time_toString },
-    { "nativeParse",             "(Ljava/lang/String;)Z",                       (void*)android_text_format_Time_parse },
-    { "nativeParse3339",         "(Ljava/lang/String;)Z",                       (void*)android_text_format_Time_parse3339 },
-    { "setToNow",                "()V",                                         (void*)android_text_format_Time_setToNow },
-    { "toMillis",                "(Z)J",                                        (void*)android_text_format_Time_toMillis },
-    { "set",                     "(J)V",                                        (void*)android_text_format_Time_set }
-};
-
-int register_android_text_format_Time(JNIEnv* env)
-{
-    jclass timeClass = env->FindClass("android/text/format/Time");
-
-    g_timeClass = (jclass) env->NewGlobalRef(timeClass);
-
-    g_allDayField = env->GetFieldID(timeClass, "allDay", "Z");
-    g_secField = env->GetFieldID(timeClass, "second", "I");
-    g_minField = env->GetFieldID(timeClass, "minute", "I");
-    g_hourField = env->GetFieldID(timeClass, "hour", "I");
-    g_mdayField = env->GetFieldID(timeClass, "monthDay", "I");
-    g_monField = env->GetFieldID(timeClass, "month", "I");
-    g_yearField = env->GetFieldID(timeClass, "year", "I");
-    g_wdayField = env->GetFieldID(timeClass, "weekDay", "I");
-    g_ydayField = env->GetFieldID(timeClass, "yearDay", "I");
-    g_isdstField = env->GetFieldID(timeClass, "isDst", "I");
-    g_gmtoffField = env->GetFieldID(timeClass, "gmtoff", "J");
-    g_timezoneField = env->GetFieldID(timeClass, "timezone", "Ljava/lang/String;");
-
-    g_shortMonthsField = env->GetStaticFieldID(timeClass, "sShortMonths", "[Ljava/lang/String;");
-    g_longMonthsField = env->GetStaticFieldID(timeClass, "sLongMonths", "[Ljava/lang/String;");
-    g_longStandaloneMonthsField = env->GetStaticFieldID(timeClass, "sLongStandaloneMonths", "[Ljava/lang/String;");
-    g_shortWeekdaysField = env->GetStaticFieldID(timeClass, "sShortWeekdays", "[Ljava/lang/String;");
-    g_longWeekdaysField = env->GetStaticFieldID(timeClass, "sLongWeekdays", "[Ljava/lang/String;");
-    g_timeOnlyFormatField = env->GetStaticFieldID(timeClass, "sTimeOnlyFormat", "Ljava/lang/String;");
-    g_dateOnlyFormatField = env->GetStaticFieldID(timeClass, "sDateOnlyFormat", "Ljava/lang/String;");
-    g_dateTimeFormatField = env->GetStaticFieldID(timeClass, "sDateTimeFormat", "Ljava/lang/String;");
-    g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;");
-    g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;");
-    g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;");
-    g_localeField = env->GetStaticFieldID(timeClass, "sLocale", "Ljava/util/Locale;");
-
-    return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 0a259aa..3cd031e 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -620,8 +620,7 @@
 static void renderText(DisplayListRenderer* renderer, const jchar* text, int count,
         jfloat x, jfloat y, int bidiFlags, Paint* paint, TypefaceImpl* typeface) {
     Layout layout;
-    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-    layout.doLayout(text, 0, count, count, css);
+    MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
     x += MinikinUtils::xOffsetForTextAlign(paint, layout);
     renderTextLayout(renderer, &layout, x, y, paint);
 }
@@ -655,8 +654,7 @@
         SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, Paint* paint,
         TypefaceImpl* typeface) {
     Layout layout;
-    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-    layout.doLayout(text, 0, count, count, css);
+    MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
     hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path);
     Paint::Align align = paint->getTextAlign();
     paint->setTextAlign(Paint::kLeft_Align);
@@ -670,8 +668,7 @@
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
         int bidiFlags, Paint* paint, TypefaceImpl* typeface) {
     Layout layout;
-    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
-    layout.doLayout(text, start, count, contextCount, css);
+    MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
     x += MinikinUtils::xOffsetForTextAlign(paint, layout);
     renderTextLayout(renderer, &layout, x, y, paint);
 }
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 1f3909a..3b6f0eb 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -117,6 +117,17 @@
     return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC);
 }
 
+static jboolean android_view_RenderNode_setClipBounds(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr, jint left, jint top, jint right, jint bottom) {
+    android::uirenderer::Rect clipBounds(left, top, right, bottom);
+    return SET_AND_DIRTY(setClipBounds, clipBounds, RenderNode::GENERIC);
+}
+
+static jboolean android_view_RenderNode_setClipBoundsEmpty(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr) {
+    return SET_AND_DIRTY(setClipBoundsEmpty,, RenderNode::GENERIC);
+}
+
 static jboolean android_view_RenderNode_setProjectBackwards(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean shouldProject) {
     return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC);
@@ -282,12 +293,12 @@
 }
 
 static jboolean android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float offset) {
+        jobject clazz, jlong renderNodePtr, jint offset) {
     return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X);
 }
 
 static jboolean android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, float offset) {
+        jobject clazz, jlong renderNodePtr, jint offset) {
     return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
 }
 
@@ -313,30 +324,6 @@
     return renderNode->stagingProperties().getAlpha();
 }
 
-static jfloat android_view_RenderNode_getLeft(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    return renderNode->stagingProperties().getLeft();
-}
-
-static jfloat android_view_RenderNode_getTop(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    return renderNode->stagingProperties().getTop();
-}
-
-static jfloat android_view_RenderNode_getRight(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    return renderNode->stagingProperties().getRight();
-}
-
-static jfloat android_view_RenderNode_getBottom(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    return renderNode->stagingProperties().getBottom();
-}
-
 static jfloat android_view_RenderNode_getCameraDistance(JNIEnv* env,
         jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -488,6 +475,8 @@
     { "nSetStaticMatrix",      "(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
     { "nSetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
     { "nSetClipToBounds",      "(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
+    { "nSetClipBounds",        "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
+    { "nSetClipBoundsEmpty",   "(J)Z",   (void*) android_view_RenderNode_setClipBoundsEmpty },
     { "nSetProjectBackwards",  "(JZ)Z",  (void*) android_view_RenderNode_setProjectBackwards },
     { "nSetProjectionReceiver","(JZ)Z",  (void*) android_view_RenderNode_setProjectionReceiver },
 
@@ -518,16 +507,12 @@
     { "nSetRight",             "(JI)Z",  (void*) android_view_RenderNode_setRight },
     { "nSetBottom",            "(JI)Z",  (void*) android_view_RenderNode_setBottom },
     { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
-    { "nOffsetLeftAndRight",   "(JF)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
-    { "nOffsetTopAndBottom",   "(JF)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
+    { "nOffsetLeftAndRight",   "(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
+    { "nOffsetTopAndBottom",   "(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
 
     { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
     { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
     { "nGetAlpha",                "(J)F",  (void*) android_view_RenderNode_getAlpha },
-    { "nGetLeft",                 "(J)F",  (void*) android_view_RenderNode_getLeft },
-    { "nGetTop",                  "(J)F",  (void*) android_view_RenderNode_getTop },
-    { "nGetRight",                "(J)F",  (void*) android_view_RenderNode_getRight },
-    { "nGetBottom",               "(J)F",  (void*) android_view_RenderNode_getBottom },
     { "nGetCameraDistance",       "(J)F",  (void*) android_view_RenderNode_getCameraDistance },
     { "nGetScaleX",               "(J)F",  (void*) android_view_RenderNode_getScaleX },
     { "nGetScaleY",               "(J)F",  (void*) android_view_RenderNode_getScaleY },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 988d461..d183d8e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -219,9 +219,11 @@
 
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
         jint width, jint height,
-        jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) {
+        jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius,
+        jint ambientShadowAlpha, jint spotShadowAlpha) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->setup(width, height, Vector3(lightX, lightY, lightZ), lightRadius);
+    proxy->setup(width, height, (Vector3){lightX, lightY, lightZ}, lightRadius,
+            ambientShadowAlpha, spotShadowAlpha);
 }
 
 static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
@@ -358,7 +360,7 @@
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
-    { "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup },
+    { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
     { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 30629ad..6a7501d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1095,6 +1095,13 @@
     <permission android:name="android.permission.TV_INPUT_HARDWARE"
         android:protectionLevel="signatureOrSystem" />
 
+    <!-- @SystemApi Allows to capture a frame of TV input hardware such as
+         built-in tuners and HDMI-in's.
+         @hide <p>Not for use by third-party applications.
+    -->
+    <permission android:name="android.permission.CAPTURE_TV_INPUT"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- @hide Allows enabling/disabling OEM unlock
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.OEM_UNLOCK_STATE"
@@ -2791,6 +2798,13 @@
         android:description="@string/permdesc_createMediaProjection"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to read install sessions
+         @hide This is not a third-party API (intended for system apps). -->
+    <permission android:name="android.permission.READ_INSTALL_SESSIONS"
+        android:label="@string/permlab_readInstallSessions"
+        android:description="@string/permdesc_readInstallSessions"
+        android:protectionLevel="signature|system" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
@@ -3009,6 +3023,11 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.server.backup.FullBackupJob"
+                 android:exported="true"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
         <service
             android:name="com.android.server.pm.BackgroundDexOptService"
             android:exported="true"
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png
index f0910d8..6c36eae 100644
--- a/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png
+++ b/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png
index a0501b3..f7382d3 100644
--- a/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png
index cac32b5..f7382d3 100644
--- a/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png
index e196bbe..6674351 100644
--- a/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png
+++ b/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png
index c5de768..0fb57b2 100644
--- a/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png
index 9137fea..0fb57b2 100644
--- a/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index d1e2df3..fb52830 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -13,27 +13,28 @@
     limitations under the License.
 -->
 
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size android:width="400dp" android:height="400dp"/>
-
-    <viewport android:viewportHeight="25" android:viewportWidth="25" />
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="400dp"
+        android:height="400dp"
+        android:viewportHeight="25"
+        android:viewportWidth="25" >
 
     <path
         android:name="torso"
         android:pathData="m2,2 l21,0 l0,21 l-21,0 z"
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         />
 
     <path
         android:name="|"
         android:pathData="m4,4 l8,0 l0,17 l-8,0 z"
-        android:fill="#FF0000FF"
+        android:fillColor="#FF0000FF"
         />
 
     <path
         android:name="_"
         android:pathData="m5,14 l16,0 l0,6 l-16,0 z"
-        android:fill="#FFFF0000"
+        android:fillColor="#FFFF0000"
         />
 
 </vector>
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 6b3be4a..1fee2df 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -13,10 +13,11 @@
     limitations under the License.
 -->
 
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size android:width="25dp" android:height="25dp"/>
-
-    <viewport android:viewportHeight="25" android:viewportWidth="25" />
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="25dp"
+        android:height="25dp"
+        android:viewportHeight="25"
+        android:viewportWidth="25" >
 
     <path
         android:name="L-card"
@@ -34,7 +35,7 @@
         M15,2 l3,0 l0,5 l5,0 l0,3 l-8,0
 
         z"
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         />
 
 
diff --git a/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png
index 4385b2b..27bdcb7 100644
--- a/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png
+++ b/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png
index 4602b35..05cfab7 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png
index 513ee8b..05cfab7 100644
--- a/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png
index ca15853..c2d6a54 100644
--- a/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png
+++ b/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png
index cb295a3..6f60bd3 100644
--- a/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png
index 81b13aa..6f60bd3 100644
--- a/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_ab_back_mtrl_am_alpha.png b/core/res/res/drawable-xxxhdpi/ic_ab_back_mtrl_am_alpha.png
new file mode 100644
index 0000000..70c2040
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_menu_search_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/ic_menu_search_mtrl_alpha.png
new file mode 100644
index 0000000..2a28f0f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_search_api_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/ic_search_api_mtrl_alpha.png
new file mode 100644
index 0000000..c873e9b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_material_anim.xml b/core/res/res/drawable/btn_radio_material_anim.xml
index 0be590e..121e544 100644
--- a/core/res/res/drawable/btn_radio_material_anim.xml
+++ b/core/res/res/drawable/btn_radio_material_anim.xml
@@ -16,42 +16,52 @@
 
 <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:state_checked="true">
-        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+        <bitmap
+            android:src="@drawable/btn_radio_to_on_mtrl_015"
+            android:tint="?attr/colorControlActivated"
+            android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_enabled="false">
-        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+        <bitmap
+            android:src="@drawable/btn_radio_to_on_mtrl_000"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_checked="true" android:id="@+id/on">
-        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+        <bitmap
+            android:src="@drawable/btn_radio_to_on_mtrl_015"
+            android:tint="?attr/colorControlActivated" />
     </item>
     <item android:id="@+id/off">
-        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+        <bitmap
+            android:src="@drawable/btn_radio_to_on_mtrl_000"
+            android:tint="?attr/colorControlNormal" />
     </item>
     <transition android:fromId="@+id/off" android:toId="@+id/on">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
                 <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
@@ -106,28 +116,28 @@
                 <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlNormal" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/ic_audio_ring_notif.xml b/core/res/res/drawable/ic_audio_ring_notif.xml
index b52db5c..60a98ab 100644
--- a/core/res/res/drawable/ic_audio_ring_notif.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="32dp"
-        android:height="32dp"/>
-
-    <viewport
+        android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#8A000000"
+        android:fillColor="#8A000000"
         android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
 </vector>
diff --git a/core/res/res/drawable/ic_audio_ring_notif_mute.xml b/core/res/res/drawable/ic_audio_ring_notif_mute.xml
index 8d7d6cb..17dfa7e 100644
--- a/core/res/res/drawable/ic_audio_ring_notif_mute.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif_mute.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="32dp"
-        android:height="32dp"/>
-
-    <viewport
+        android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#8A000000"
+        android:fillColor="#8A000000"
         android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
 </vector>
diff --git a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
index 2f1d940..2ed33ea 100644
--- a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="32dp"
-        android:height="32dp"/>
-
-    <viewport
+        android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#8A000000"
+        android:fillColor="#8A000000"
         android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
 </vector>
diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml
index 16c101b..e185fc4 100644
--- a/core/res/res/drawable/ic_corp_badge.xml
+++ b/core/res/res/drawable/ic_corp_badge.xml
@@ -13,31 +13,28 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="20.0dp"
-        android:height="20.0dp"/>
-
-    <viewport
+        android:height="20.0dp"
         android:viewportWidth="20.0"
-        android:viewportHeight="20.0"/>
+        android:viewportHeight="20.0">
 
     <path
         android:pathData="M10.0,10.0m-10.0,0.0a10.0,10.0 0.0,1.0 1.0,20.0 0.0a10.0,10.0 0.0,1.0 1.0,-20.0 0.0"
-        android:fill="#FF5722"/>
+        android:fillColor="#FF5722"/>
     <path
         android:pathData="M11.139,12.149l-0.001,0.0L8.996,12.149l0.0,-0.571L4.738,11.578l-0.002,2.198c0.0,0.589 0.477,1.066 1.066,1.066l8.535,0.0c0.589,0.0 1.066,-0.477 1.066,-1.066l0.0,-2.198l-4.264,0.0L11.139,12.149z"
-        android:fill="#FFFFFF"/>
+        android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M8.996,10.006l2.143,0.0l0.0,0.52l4.442,0.0L15.580999,7.909c0.0,-0.589 -0.477,-1.066 -1.066,-1.066l-1.877,0.0L7.544,6.843L5.606,6.843c-0.589,0.0 -1.061,0.477 -1.061,1.066l-0.003,2.617l4.453,0.0L8.996,10.006L8.996,10.006z"
-        android:fill="#FFFFFF"/>
+        android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M3.367,3.456 h13.016 v13.016 h-13.016z"
-        android:fill="#00000000"/>
+        android:fillColor="#00000000"/>
     <path
         android:pathData="M7.368,5.263l5.263,0.0l0.0,1.053l-5.263,0.0z"
-        android:fill="#FFFFFF"/>
+        android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M8.996,12.149l2.1419992,0.0 0.0010004044,0.0 0.0,-0.5699997 -2.1429996,0.0z"
-        android:fill="#00000000"/>
+        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_corp_icon_badge.xml b/core/res/res/drawable/ic_corp_icon_badge.xml
index c8e49e1..d20c431 100644
--- a/core/res/res/drawable/ic_corp_icon_badge.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge.xml
@@ -13,42 +13,39 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64.0dp"
-        android:height="64.0dp"/>
-
-    <viewport
+        android:height="64.0dp"
         android:viewportWidth="64.0"
-        android:viewportHeight="64.0"/>
+        android:viewportHeight="64.0">
 
     <path
-        android:fill="#FF000000"
+        android:fillColor="#FF000000"
         android:pathData="M49.062,50.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
         android:fillOpacity="0.2"/>
     <path
-        android:fill="#FF000000"
+        android:fillColor="#FF000000"
         android:pathData="M49.0,49.5m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
         android:fillOpacity="0.2"/>
     <path
         android:pathData="M49.0,49.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
-        android:fill="#FF5722"/>
+        android:fillColor="#FF5722"/>
     <path
         android:pathData="M50.594,52.009l-3.0,0.0L47.594,51.0l-5.961,0.0l-0.003,3.289c0.0,0.826 0.668,1.494 1.494,1.494l11.948,0.0c0.826,0.0 1.494,-0.668 1.494,-1.494L56.566006,51.0l-5.972,0.0C50.594,51.0 50.594,52.009 50.594,52.009z"
-        android:fill="#FFFFFF"/>
+        android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M47.594,49.009l3.0,0.0L50.594,50.0l6.22,0.0l0.0,-3.925c0.0,-0.826 -0.668,-1.494 -1.494,-1.494l-2.627,0.0l-7.131,-0.001l-2.713,0.0c-0.826,0.0 -1.486,0.668 -1.486,1.494L41.359,50.0l6.235,0.0L47.594,49.009z"
-        android:fill="#FFFFFF"/>
+        android:fillColor="#FFFFFF"/>
     <path
         android:pathData="M39.714,39.838 h18.221 v18.221 h-18.221z"
-        android:fill="#00000000"/>
+        android:fillColor="#00000000"/>
     <path
         android:pathData="M47.594,49.009 h3.0 v0.991 h-3.0z"
-        android:fill="#00000000"/>
+        android:fillColor="#00000000"/>
     <path
         android:pathData="M47.594,51.0 h3.0 v1.009 h-3.0z"
-        android:fill="#00000000"/>
+        android:fillColor="#00000000"/>
     <path
         android:pathData="M46.0,43.0l6.0,0.0l0.0,1.0l-6.0,0.0z"
-        android:fill="#FFFFFF"/>
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/core/res/res/drawable/ic_lock_bugreport.xml b/core/res/res/drawable/ic_lock_bugreport.xml
index b93a09a..8540eee 100644
--- a/core/res/res/drawable/ic_lock_bugreport.xml
+++ b/core/res/res/drawable/ic_lock_bugreport.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="32dp"
-        android:height="32dp"/>
-
-    <viewport
+        android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="?attr/colorControlNormal"
+        android:fillColor="?attr/colorControlNormal"
         android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/>
 </vector>
diff --git a/core/res/res/drawable/stat_notify_disabled_data.xml b/core/res/res/drawable/stat_notify_disabled_data.xml
index d287a75..2f6ffaf 100644
--- a/core/res/res/drawable/stat_notify_disabled_data.xml
+++ b/core/res/res/drawable/stat_notify_disabled_data.xml
@@ -13,25 +13,22 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
-        android:height="24dp"/>
-
-    <viewport
+        android:height="24dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M40.709,4.5l-6.604,7.337 0.0,16.601 6.604,6.604z"/>
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M32.305,13.838l-6.0629997,6.7370005 6.0629997,6.0629997z"/>
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M15.498,40.5l0.0,-7.9869995 -7.205,7.9869995z"/>
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M10.265,9.72l-2.5460005,2.545 9.971001,9.971 3.7139988,3.7140007 -4.105999,4.5619984 0.0,9.988001 6.6019993,0.0 0.0,-12.054001 1.8029995,1.8030014 0.0,10.250999 6.602001,0.0 0.0,-3.6479988 1.7999992,1.7999992 1.8479996,1.8479996 4.670002,4.669998 2.5459976,-2.5459976z"/>
 </vector>
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
index 6e0840c..3bf3cd7 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="76dp"
-        android:width="76dp" />
-
-    <viewport
+        android:width="76dp"
         android:viewportHeight="48"
-        android:viewportWidth="48" />
+        android:viewportWidth="48" >
 
     <group
         android:name="root"
@@ -29,9 +25,9 @@
         android:translateY="24.0" >
         <path
             android:name="progressBar"
-            android:fill="#00000000"
+            android:fillColor="#00000000"
             android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
-            android:stroke="?attr/colorControlActivated"
+            android:strokeColor="?attr/colorControlActivated"
             android:strokeLineCap="round"
             android:strokeLineJoin="miter"
             android:strokeWidth="4"
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
index 7f1231c..62f9225 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="48dp"
-        android:width="48dp" />
-
-    <viewport
+        android:width="48dp"
         android:viewportHeight="48"
-        android:viewportWidth="48" />
+        android:viewportWidth="48" >
 
     <group
         android:name="root"
@@ -29,9 +25,9 @@
         android:translateY="24.0" >
         <path
             android:name="progressBar"
-            android:fill="#00000000"
+            android:fillColor="#00000000"
             android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
-            android:stroke="?attr/colorControlActivated"
+            android:strokeColor="?attr/colorControlActivated"
             android:strokeLineCap="round"
             android:strokeLineJoin="miter"
             android:strokeWidth="4"
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
index 58ca101..1352cfc 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="16dp"
-        android:width="16dp" />
-
-    <viewport
+        android:width="16dp"
         android:viewportHeight="48"
-        android:viewportWidth="48" />
+        android:viewportWidth="48" >
 
     <group
         android:name="root"
@@ -29,9 +25,9 @@
         android:translateY="24.0" >
         <path
             android:name="progressBar"
-            android:fill="#00000000"
+            android:fillColor="#00000000"
             android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
-            android:stroke="?attr/colorControlActivated"
+            android:strokeColor="?attr/colorControlActivated"
             android:strokeLineCap="round"
             android:strokeLineJoin="miter"
             android:strokeWidth="4"
diff --git a/core/res/res/layout/app_not_authorized.xml b/core/res/res/layout/app_not_authorized.xml
index bd40eeb..2188511 100644
--- a/core/res/res/layout/app_not_authorized.xml
+++ b/core/res/res/layout/app_not_authorized.xml
@@ -32,7 +32,7 @@
         android:paddingBottom="16dip"
         android:paddingStart="16dip"
         android:paddingEnd="16dip"
-        android:text="@string/app_no_restricted_accounts"
+        android:text="@string/error_message_change_not_allowed"
     />
 
     <!-- Horizontal divider line -->
diff --git a/core/res/res/layout/app_permission_item.xml b/core/res/res/layout/app_permission_item.xml
index e2ffffb..1eff3dc 100644
--- a/core/res/res/layout/app_permission_item.xml
+++ b/core/res/res/layout/app_permission_item.xml
@@ -27,8 +27,8 @@
 
     <ImageView
         android:id="@+id/perm_icon"
-        android:layout_width="32dp"
-        android:layout_height="32dp"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
         android:layout_marginStart="16dp"
         android:layout_marginEnd="8dp"
         android:scaleType="fitCenter" />
diff --git a/core/res/res/layout/app_permission_item_money.xml b/core/res/res/layout/app_permission_item_money.xml
index 3fa4653..7e1aca1 100644
--- a/core/res/res/layout/app_permission_item_money.xml
+++ b/core/res/res/layout/app_permission_item_money.xml
@@ -27,8 +27,8 @@
 
     <ImageView
         android:id="@+id/perm_icon"
-        android:layout_width="32dp"
-        android:layout_height="32dp"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
         android:layout_marginStart="16dp"
         android:layout_marginEnd="8dp"
         android:scaleType="fitCenter" />
diff --git a/core/res/res/layout/app_permission_item_old.xml b/core/res/res/layout/app_permission_item_old.xml
index ce0cd42..de6fc4f 100644
--- a/core/res/res/layout/app_permission_item_old.xml
+++ b/core/res/res/layout/app_permission_item_old.xml
@@ -26,8 +26,8 @@
 
     <ImageView
         android:id="@+id/perm_icon"
-        android:layout_width="30dip"
-        android:layout_height="30dip"
+        android:layout_width="24dip"
+        android:layout_height="24dip"
         android:layout_alignParentStart="true"
         android:scaleType="fitCenter" />
 
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 1a7324a..b5b5b27 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -93,8 +93,7 @@
                 android:dropDownHeight="wrap_content"
                 android:dropDownAnchor="@id/search_edit_frame"
                 android:dropDownVerticalOffset="0dip"
-                android:dropDownHorizontalOffset="0dip"
-                android:contentDescription="@string/searchview_description_query" />
+                android:dropDownHorizontalOffset="0dip" />
 
             <ImageView
                 android:id="@+id/search_close_btn"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a0e4e98..0545370 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Laat die program toe om Bluetooth-MAP-boodskappe te ontvang en te verwerk. Dit beteken dat die program boodskappe wat na jou toestel gestuur word, kan monitor of uitvee sonder dat jy dit gesien het."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"haal lopende programme op"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Laat die program toe om inligting oor die huidig- en onlangslopende take op te haal. Dit kan moontlik die program toelaat om inligting oor watter programme op die toestel gebruik word, te ontdek."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interaksie tussen gebruikers"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Laat die program toe om aksies vir verskillende gebruikers op die toestel uit te voer. Kwaadwillige programme kan dit gebruik om die beskerming tussen gebruikers te skend."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volle lisensie vir interaksie tussen gebruikers"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Laat die program toe om die blaaier se geskiedenis of boekmerke wat op jou foon gestoor is, te verander. Dit kan moontlik die program toelaat om blaaierdata uit te vee of te verander. Let wel: hierdie toestemming mag dalk nie deur derdeparty-blaaiers of ander programme met webblaaivermoëns afgedwing word nie."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"stel \'n wekker"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Laat die program toe om \'n alarm in \'n geïnstalleerde wekkerprogram te stel. Sommige wekkerprogramme werk dalk nie met hierdie funksie nie."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"skryf stemposse"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Laat die program toe om boodskappe uit jou stemposinkassie te wysig en te verwyder."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"voeg stemboodskap by"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Laat die program toe om boodskappe by te voeg by jou stempos-inkassie."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"lees stempos"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Laat die program toe om jou stemposse te lees."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"verander blaaier se geoligging-toestemmings"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Laat die program toe om die blaaier se geoligging-toestemmings te verander. Kwaadwillige programme kan dit gebruik om hulle toe te laat om ligginginligting aan enige webwerf te stuur."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"verifieer pakkies"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Stelsel"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadlose skerm"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Koppel aan toestel"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Saai skerm uit na toestel"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Soek tans vir toestelle…"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index fc9a8c8..ebbbdf0 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"መተግበሪያው የብሉቱዝ ኤምኤፒ መልእክቶችን እንዲቀበልና እንዲያካሂድ ይፈቅድለታል። ይህ ማለት መተግበሪያው ወደመሳሪያዎ የተላኩ መልእክቶችን ለእርስዎ ሳያሳይ ሊከታተል ወይም ሊሰረዝ ይችላል ማለት ነው።"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"አሂድ መተግበሪያዎችን ሰርስረው ያውጡ"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"መተግበሪያው በአሁኑ ጊዜና በቅርቡ እየተካሄዱ ስላሉ ተግባሮችን መረጃ ሰርስሮ እንዲያወጣ ይፈቅድለታል። ይህ መተግበሪያው በመሳሪያው ላይ የትኛዎቹ መተግበሪያዎች ጥቅም ላይ ስለመዋላቸው መረጃ እንዲያገኝ ሊፈቅድለት ይችላል።"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር መፍጠር"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"መተግበሪያው በመሣሪያው ላይ በተለያዩ ተጠቃሚዎች ላይ እርምጃዎችን እንዲፈጽም ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች ይህንን ተጠቅመው በተጠቃሚዎች መካከል ያለውን ጥበቃ ሊጥሱ ይችላሉ።"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር ለመፍጠር ሙሉ ፍቃድ"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"መተግበሪያው ስልክህ ላይ የተከማቹ የአሳሹን ታሪክ ወይም ዕልባቶችን እንዲቀይር ይፈቅድለታል። ይህ መተግበሪያው የአሳሽ ውሂብ እንዲያጠፋ ወይም እንዲያስተካክል ሊፈቅድለት ይችላል። ማስታወሻ፦ ይህ ፈቃድ በሶስተኛ ወገን አሳሾች ወይም በሌላ የድር አሳሽነት አቅም ባላቸው መተግበሪያዎች ላይፈጸም ይችላል።"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"ማንቂያ አስቀምጥ"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"በተጫነው የማንቂያ ሰዓት መተግበሪያ ውስጥ ማንቅያን ለማደራጀት ለመተግበሪያው ይፈቅዳሉ፡፡አንዳንድ የማንቂያ ሰዓት መተግበሪያዎች ይሄንን ባህሪ ላይፈፅሙ ይችላሉ፡፡"</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"የድምጽ መልእክቶችን ይጻፉ"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"መተግበሪያው ከድምጽ መልእክት የገቢ መልእክት ሳጥንዎ ውስጥ መልእክቶችን እንዲያስተካክልና እንዲያስወግድ ይፈቅዳል።"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"የድምፅ መልዕክት አክል"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ወደ ድምፅ መልዕክት የገቢ መልዕክትህ መልዕክቶች ለማከል ለመተግበሪያው ይፈቅዳሉ።"</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"ፓኬጆችን አረጋግጥ"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ስርዓት"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"የብሉቱዝ ድምጽ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ገመድ አልባ ማሳያ"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"የሚዲያ ውጽዓት"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"ከመሳሪያ ጋር ያገናኙ"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ማያ ገጽን ወደ መሣሪያ ይውሰዱ"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"መሳሪያዎችን በመፈለግ ላይ…"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 2077543..eb17630 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"‏يسمح للتطبيق بتلقي رسائل بلوتوث MAP ومعالجتها. وهذا يعني أنه سيكون بإمكان التطبيق الإشراف على أو حذف الرسائل المرسلة إليك بدون عرضها لك."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"استرداد التطبيقات التي قيد التشغيل"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"للسماح للتطبيق باسترداد معلومات حول المهام التي يجري تشغيلها حاليًا والتي تم تشغيلها مؤخرًا. وقد يسمح هذا للتطبيق باكتشاف معلومات حول التطبيقات المستخدمة على الجهاز."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"التعامل بين المستخدمين"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"للسماح للتطبيق بتنفيذ إجراءات بين مستخدمين مختلفين على الجهاز. قد تستخدم التطبيقات الضارة ذلك لانتهاك الحماية بين المستخدمين."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"الترخيص بالكامل للتعامل بين المستخدمين"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"النظام"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"عرض شاشة لاسلكي"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"الاتصال بجهاز"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"بث الشاشة على الجهاز"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"جارٍ البحث عن الأجهزة…"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b87db9b..8c7da0f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Разрешава на приложението да получава и обработва съобщения чрез Bluetooth MAP. Това означава, че то може да наблюдава или изтрива изпратените до устройството ви, без да ви ги покаже."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"извличане на изпълняваните приложения"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Разрешава на приложението да извлича информация за задачите, изпълнявани понастоящем и неотдавна. Това може да му позволи да открива данни за това, кои приложения се използват на устройството."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"взаимодействие с потребителите"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Разрешава на приложението да изпълнява действия за различни потребители на устройството. Злонамерените приложения може да използват това, за да нарушат защитата между потребителите."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"пълен лиценз за взаимодействие с потребителите"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен дисплей"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Свързване с устройство"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Екран за предаване към устройството"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Търсят се устройства…"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 81fee3a..8c1318d 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP বার্তা পেতে ও প্রক্রিয়া করতে অ্যাপ্লিকেশানটিকে অনুমতি দিন। এর অর্থ হলো, অ্যাপ্লিকেশানটি আপনাকে না দেখিয়েই আপনার ডিভাইসে পাঠানো বার্তা পর্যবেক্ষণ বা মুছতে পারবে।"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"চলমান অ্যাপ্লিকেশান উদ্ধার করে"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"বর্তমানে ও সাম্প্রতিককালের সক্রিয় ক্রিয়াগুলি সম্বন্ধে তথ্য পুনরুদ্ধার করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এছাড়া এটি ডিভাইসটিতে কোন অ্যাপ্লিকেশানগুলি ব্যবহৃত হচ্ছে তার বিষয়ে তথ্য খুঁজে বের করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করতে পারে৷"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"সামগ্রী ব্যবহারকারীদের সাথে ইন্টারঅ্যাক্ট করুন"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ডিভাইসটিতে থাকা বিভিন্ন ব্যবহারকারীর মধ্যে ক্রিয়াগুলির কার্য-সম্পাদনা করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি এটিকে ব্যবহারকারীদের মধ্যে সুরক্ষা লঙ্ঘন করতে ব্যবহার করতে পারে৷"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ব্যবহারকারীদের সাথে ইন্টারঅ্যাক্ট করার সম্পূর্ণ লাইসেন্স"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"অ্যাপ্লিকেশানটিকে আপনার ফোনে সঞ্চিত ব্রাউজারের ইতিহাস বা বুকমার্কগুলি পরিবর্তন করতে দেয়৷ এটি অ্যাপ্লিকেশানটিকে ব্রাউজার ডেটা মুছে দিতে বা পরিবর্তন করতে দেয়৷ দ্রষ্টব্য: এই অনুমতি তৃতীয় পক্ষের ব্রাউজারগুলির বা ওয়েব ব্রাউজিং ক্ষমতা সম্পন্ন অন্যান্য অ্যাপ্লিকেশানগুলি দ্বারা বলবৎ নাও হতে পারে৷"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"একটি অ্যালার্ম সেট করুন"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"অ্যাপ্লিকেশানকে একটি ইনস্টল থাকা অ্যালার্ম অ্যাপ্লিকেশানে একটি অ্যালার্ম সেট করতে দেয়৷ কিছু অ্যালার্ম ঘড়ি অ্যাপ্লিকেশানগুলিতে ভবিষ্যতে এটি লাগু নাও হতে পারে৷"</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"ভয়েসমেলগুলি লিখুন"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"অ্যাপ্লিকেশানটিকে আপনার ভয়েসমেল ইনবক্স থেকে বার্তা পরিবর্তনের ও সরানোর অনুমতি দেয়৷"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ভয়েসমেল যোগ করে"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"অ্যাপ্লিকেশানকে আপনার ভয়েসমেইল ইনবক্সে বার্তা যোগ করার অনুমতি দেয়৷"</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"প্যাকেজগুলি যাচাই করে"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"সিস্টেম"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth অডিও"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ওয়্যারলেস প্রদর্শন"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"মিডিয়া আউটপুট"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"ডিভাইসে সংযোগ করুন"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ডিভাইসে স্ক্রীণ কাস্ট করুন"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"ডিভাইসগুলি অনুসন্ধান করা হচ্ছে…"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 7e69339..b61a863 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permet que l\'aplicació rebi i processi missatges de Bluetooth MAP. Això vol dir que l\'aplicació pot controlar o suprimir missatges que s\'hagin enviat al teu dispositiu sense mostrar-te\'ls."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"recupera les aplicacions en execució"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permet que l\'aplicació recuperi informació sobre les tasques que s\'executen actualment i les que s\'han executat recentment. Aquesta acció pot permetre que l\'aplicació descobreixi informació sobre les aplicacions que s\'utilitzen al dispositiu."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interacciona entre usuaris"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet que l\'aplicació dugui a terme accions en diferents usuaris del dispositiu. Les aplicacions malicioses poden fer servir aquest permís per infringir la protecció entre usuaris."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"llicència completa per interaccionar entre usuaris"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla sense fil"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortida de contingut multimèdia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexió al dispositiu"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emissió de pantalla al dispositiu"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"S\'estan cercant dispositius…"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 01c2cef..ffafe62 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Umožňuje aplikaci přijímat a zpracovat zprávy Bluetooth MAP. To znamená, že aplikace může sledovat a mazat zprávy odeslané do zařízení, aniž by vám je zobrazila."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"načtení spuštěných aplikací"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Umožňuje aplikaci získat informace o aktuálně a naposledy spuštěných úlohách. Aplikace s tímto oprávněním může odhalit informace o aplikacích, které se v zařízení používají."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakce napříč uživateli"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umožňuje aplikaci provádět akce napříč různými uživateli zařízení. Škodlivé aplikace toto oprávnění mohou zneužít k obejití ochrany mezi uživateli."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"úplné oprávnění k interakcím napříč uživateli"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrátový displej"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Připojení k zařízení"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odesílání obsahu obrazovky do zařízení"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Vyhledávání zařízení…"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 95bd92f..5067669 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Tillader, at appen kan modtage og behandle Bluetooth MAP-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"hente kørende apps"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Tillader, at appen kan hente oplysninger om nuværende og seneste opgaver. Med denne tilladelse kan appen finde oplysninger om, hvilke applikationer der bruges på enheden."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kommunikere på tværs af brugere"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillader, at appen udfører handlinger på tværs af forskellige brugere på enheden. Ondsindede apps kan bruge dette til at krænke beskyttelsen mellem brugere."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fuld licens til at kommunikere på tværs af brugere"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skærm"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieudgang"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Opret forbindelse til enheden"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Send skærm til enhed"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søger efter enheder…"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b373ecd..2bea178 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Ermöglicht der App, Bluetooth MAP-Mitteilungen zu empfangen und zu verarbeiten. Das bedeutet, dass die App an Ihr Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie Ihnen anzuzeigen."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"Aktive Apps abrufen"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Ermöglicht der App, Informationen zu aktuellen und kürzlich ausgeführten Aufgaben abzurufen. Damit kann die App möglicherweise ermitteln, welche Apps auf Ihrem Gerät zum Einsatz kommen."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Nutzerübergreifend interagieren"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ermöglicht der App, auf dem Gerät nutzerübergreifend Aktionen durchzuführen. Schädliche Apps können so den zwischen den Nutzern bestehenden Schutz aufheben."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Vollständige Lizenz zum nutzerübergreifenden Interagieren"</string>
@@ -1386,8 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ermöglicht einer App die Anbindung an einen Trust Agent-Service"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Mit Update- und Wiederherstellungssystem interagieren"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Ermöglicht einer App die Interaktion mit dem Wiederherstellungssystem und den Systemupdates"</string>
-    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sitzungen zum Projizieren von Medien"</string>
-    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ermöglicht einer App, Sitzungen zum Projizieren von Medien zu erstellen. In diesen Sitzungen können Apps Bildschirm- und Audioinhalte aufnehmen. Für normale Apps sollte dies nie erforderlich sein."</string>
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sitzungen zur Projektion von Medieninhalten erstellen"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ermöglicht einer App, Sitzungen zur Projektion von Medieninhalten zu erstellen. In diesen Sitzungen können Apps Bildschirm- und Audioinhalte aufnehmen. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Für Zoomeinstellung zweimal berühren"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Widget konnte nicht hinzugefügt werden."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Los"</string>
@@ -1512,10 +1516,10 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bearbeiten"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Warnung zum Datenverbrauch"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Für Verbrauch/Einstell. berühren"</string>
-    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G/3G-Daten sind deaktiviert"</string>
-    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G-Daten sind deaktiviert"</string>
-    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Mobilfunkdaten sind deaktiviert"</string>
-    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"WLAN-Daten sind deaktiviert"</string>
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G/3G-Daten deaktiviert"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G-Daten deaktiviert"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Mobilfunkdaten deaktiviert"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"WLAN-Daten deaktiviert"</string>
     <string name="data_usage_limit_body" msgid="6131350187562939365">"Limit erreicht"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-/3G-Datenlimit überschritten"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G-Datenlimit überschritten"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-Audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Kabellose Übertragung (WiDi)"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Medienausgabe"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Mit Gerät verbinden"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Bildschirm auf Gerät übertragen"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Geräte werden gesucht…"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index d3447b4..3e7c212 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων MAP Bluetooth. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"ανάκτηση εκτελούμενων εφαρμογών"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Επιτρέπει στην εφαρμογή την ανάκτηση πληροφοριών σχετικά με τρέχουσες και πρόσφατα εκτελούμενες εργασίες. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να ανακαλύπτει πληροφορίες σχετικά με το ποιες εφαρμογές χρησιμοποιούνται στη συσκευή."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"αλληλεπίδραση στους χρήστες"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Δίνει στην εφαρμογή τη δυνατότητα να πραγματοποιεί ενέργειες σε όλους τους διαφορετικούς χρήστες στη συσκευή. Οι κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτή τη δυνατότητα για να παραβιάσουν την προστασία μεταξύ των χρηστών."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"πλήρης άδεια αλληλεπίδρασης στους χρήστες"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Σύστημα"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ήχος Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Ασύρματη οθόνη"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Έξοδος μέσων"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Σύνδεση με τη συσκευή"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Μετάδοση οθόνης σε συσκευή"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Αναζήτηση συσκευών…"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index e7c501f..376c03b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Allows the app to receive and process Bluetooth MAP messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"retrieve running apps"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Allows the app to retrieve information about currently and recently running tasks. This may allow the app to discover information about which applications are used on the device."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interact across users"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Allows the app to perform actions across different users on the device. Malicious apps may use this to violate the protection between users."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full license to interact across users"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string>
@@ -1728,7 +1733,7 @@
   </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="done_label" msgid="2093726099505892398">"Finished"</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>
     <string name="select_hours" msgid="6043079511766008245">"Select hours"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index e7c501f..376c03b 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Allows the app to receive and process Bluetooth MAP messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"retrieve running apps"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Allows the app to retrieve information about currently and recently running tasks. This may allow the app to discover information about which applications are used on the device."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interact across users"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Allows the app to perform actions across different users on the device. Malicious apps may use this to violate the protection between users."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full license to interact across users"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string>
@@ -1728,7 +1733,7 @@
   </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="done_label" msgid="2093726099505892398">"Finished"</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>
     <string name="select_hours" msgid="6043079511766008245">"Select hours"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d5cc743..6a69085 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que la aplicación reciba y procese mensajes por Bluetooth (MAP), lo que significa que podría controlar o eliminar mensajes enviados al dispositivo sin mostrártelos."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicaciones en ejecución"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que la aplicación recupere información sobre las tareas que se estén ejecutando en ese momento o que se hayan ejecutado recientemente. La aplicación puede utilizar este permiso para descubrir cuáles son las aplicaciones que se utilizan en el dispositivo."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Interactuar con los usuarios"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que la aplicación lleve a cabo acciones entre los diferentes usuarios del dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para infringir la protección entre usuarios."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Licencia completa para interactuar con los usuarios"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite que la aplicación modifique el historial o los marcadores del navegador almacenados en el dispositivo. La aplicación puede utilizar este permiso para borrar o modificar los datos del navegador. Nota: Este permiso no puede ser utilizado por navegadores externos ni otras aplicaciones que tengan funciones de navegación por Internet."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"programar una alarma"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite que la aplicación establezca una alarma en una aplicación de alarma instalada. Es posible que algunas aplicaciones de alarma no incluyan esta función."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"Editar los mensajes del buzón de voz"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Permite que la aplicación modifique y elimine mensajes de la bandeja de entrada del buzón de voz."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"agregar correo de voz"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite que la aplicación agregue mensajes a la bandeja de entrada de tu buzón de voz."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"Consultar los mensajes del buzón de voz"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Permite que la aplicación consulte los mensajes del buzón de voz."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modificar los permisos de ubicación geográfica del navegador"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite que la aplicación modifique los permisos de ubicación geográfica del navegador. Las aplicaciones maliciosas pueden utilizar esto para permitir el envío de información de ubicación a sitios web arbitrarios."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"Verificar paquetes"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar al dispositivo"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir pantalla a dispositivo"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0405f7c..bf77e1d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que la aplicación reciba y procese mensajes por Bluetooth (MAP), lo que significa que podría utilizar este permiso para controlar o eliminar mensajes enviados al dispositivo sin mostrárselos al usuario."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicaciones en ejecución"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que aplicación recupere información sobre tareas que se están ejecutando en ese momento o que se han ejecutado recientemente. La aplicación puede utilizar este permiso para descubrir cuáles son las aplicaciones que se utilizan en el dispositivo."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interactuar con los usuarios"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que la aplicación lleve a cabo acciones entre los diferentes usuarios del dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para infringir la protección entre usuarios."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licencia completa para interactuar con los usuarios"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar a dispositivo"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Enviar pantalla a dispositivo"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 9c740c2..4f044f3 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Võimaldab rakendusel vastu võtta ja töödelda Bluetoothi MAP-sõnumeid. See tähendab, et rakendus saab teie seadmesse saadetud sõnumeid jälgida või kustutada ilma neid teile näitamata."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"Käitatud rakenduste toomine"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Võimaldab rakendusel tuua teavet praegu ja hiljuti käitatud ülesannete kohta. See võib lubada rakendusel avastada teavet selle kohta, milliseid rakendusi seadmes kasutatakse."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"toimingud erinevatel kasutajakontodel"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Lubab rakendusel teha toiminguid seadme erinevatel kasutajakontodel. Pahatahtlikud rakendused võivad kasutada seda kasutajatevahelise kaitse rikkumiseks."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"täielik litsents teha toiminguid erinevatel kasutajakontodel"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Süsteem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Juhtmeta ekraan"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Seadmega ühendamine"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekraanikuva ülekandmine seadmesse"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Seadmete otsimine …"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 2bf1850..75ef543 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP mezuak jaso eta prozesatzeko baimena ematen die aplikazioei. Horrela, aplikazioek gailura bidalitako mezuak kontrola eta ezaba ditzakete, mezuak zuri erakutsi gabe."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"Eskuratu abian diren aplikazioak"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Unean edo duela gutxi exekutatutako zereginei buruzko informazioa lortzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailuan erabiltzen ari diren aplikazioei buruzko informazioa ezagut dezake."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"erabiltzaileekin elkarrekintzan jardutea"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Gailuaren erabiltzaileetan ekintzak gauzatzeko baimena ematen die aplikazioei. Aplikazio gaiztoek erabil dezakete erabiltzaileen arteko babesa urratzeko."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"erabiltzaileekin elkarrekintzan jarduteko baimen osoa"</string>
@@ -443,9 +447,9 @@
     <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Beste aplikazioen cache-direktorioetako fitxategiak ezabatuta telefono-memorian tokia egiteko baimena ematen die aplikazioei. Hori eginez gero, beste aplikazio horiek motelago abiarazi daitezke, datuak berriro lortu beharko dituztelako."</string>
     <string name="permlab_movePackage" msgid="3289890271645921411">"Aldatu tokiz aplikazioen baliabideak"</string>
     <string name="permdesc_movePackage" msgid="319562217778244524">"Aplikazio-baliabideak barneko euskarritik kanpoko batera (eta alderantziz) eramatea baimentzen die aplikazioei."</string>
-    <string name="permlab_readLogs" msgid="6615778543198967614">"Irakurri egunkarietako isilpeko datuak"</string>
-    <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Sistemaren askotariko egunkari-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, tabletarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string>
-    <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Sistemaren askotariko egunkari-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, telefonoarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string>
+    <string name="permlab_readLogs" msgid="6615778543198967614">"Irakurri erregistroetako isilpeko datuak"</string>
+    <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Sistemaren askotariko erregistro-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, tabletarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string>
+    <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Sistemaren askotariko erregistro-fitxategiak irakurtzea baimentzen die aplikazioei. Horrela, telefonoarekin egiten ari zarenari buruzko informazio orokorra aurki dezakete, eta isilpekoa edo pertsonala den informazioa ere barne har daiteke."</string>
     <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"erreprodukziorako edozein multimedia-deskodetzaile erabiltzea"</string>
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Instalatutako edozein multimedia-deskodetzaile erabiltzeko baimena ematen die aplikazioei, gauzak erreproduzitu ahal izateko deskodetzeko."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Kudeatu kredentzial fidagarriak"</string>
@@ -1181,11 +1185,11 @@
     <string name="whichApplication" msgid="4533185947064773386">"Gauzatu ekintza hau erabilita:"</string>
     <string name="whichApplicationNamed" msgid="8260158865936942783">"Osatu ekintza %1$s erabiliz"</string>
     <string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string>
-    <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin honekin: %1$s"</string>
+    <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editatu honekin:"</string>
-    <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu honekin: %1$s"</string>
+    <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Partekatu honekin:"</string>
-    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partekatu honekin: %1$s"</string>
+    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partekatu %1$s aplikazioarekin"</string>
     <string name="whichHomeApplication" msgid="4616420172727326782">"Hautatu hasierako pantailako aplikazio bat"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Erabili modu lehenetsian ekintza honetarako."</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Garbitu aplikazio lehenetsia Sistemaren ezarpenak &gt; Aplikazioak &gt; Deskargatutakoak atalean."</string>
@@ -1386,7 +1390,7 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Konfiantza zehazteko agente baten zerbitzuari lotzea baimentzen die aplikazioei."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interaktuatu eguneratze- eta eskuratze-sistemekin"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Eskuratze-sistemarekin nahiz sistema-eguneratzeekin interaktuatzeko aukera ematen die aplikazioei."</string>
-    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sortu multimedia-elementuak proiektatzeko saioak"</string>
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Sortu multimedia-edukia proiektatzeko saioak"</string>
     <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Multimedia-elementuak proiektatzeko saioak sortzea baimentzen die aplikazioei. Saio horiekin, aplikazioek pantailan bistaratutakoa eta audioa graba ditzakete. Aplikazio normalek ez lukete behar."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ukitu birritan zooma kontrolatzeko"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Ezin izan da widgeta gehitu."</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetootharen audioa"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Hari gabeko pantaila"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Multimedia-irteera"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Konektatu gailura"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Igorri pantaila gailura"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Gailuak bilatzen…"</string>
@@ -1747,7 +1752,7 @@
     <string name="lock_to_app_negative" msgid="2259143719362732728">"EZ, ESKERRIK ASKO"</string>
     <string name="lock_to_app_positive" msgid="7085139175671313864">"HASI"</string>
     <string name="lock_to_app_start" msgid="3074665051586318340">"Aplikazio batean blokeatuta"</string>
-    <string name="lock_to_app_exit" msgid="8967089657201849300">"Pantaila ez dago jada aplikazio bakarrean blokeatuta"</string>
+    <string name="lock_to_app_exit" msgid="8967089657201849300">"Aplikazio bakarreko modutik irten egin da"</string>
     <string name="lock_to_app_use_screen_lock" msgid="1434584309048590886">"Irten aurretik, eskatu %1$s"</string>
     <string name="lock_to_app_unlock_pin" msgid="7908385370846820001">"PIN kodea"</string>
     <string name="lock_to_app_unlock_pattern" msgid="7763071104790758405">"desblokeatzeko eredua"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 596daa8..468dde4 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"‏به برنامه اجازه می‌دهد پیام‌های بلوتوث MAP را دریافت و پردازش کند. این یعنی برنامه می‌تواند پیام‌های ارسالی به دستگاه شما را بدون نمایش آن‌ها به شما حذف یا کنترل کند."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"‏بازیابی برنامه‎های در حال اجرا"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"به برنامه امکان می‌دهد اطلاعات مربوط به کارهای در حال اجرای اخیر و کنونی را بازیابی کند. این ممکن است به برنامه امکان دهد به اطلاعات مربوط به برنامه‌هایی که در دستگاه استفاده می‌شوند دست یابد."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ارتباط بین کاربران"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"به برنامه اجازه می‌دهد اقداماتی در بین کاربران مختلف در دستگاه انجام دهد. ممکن است برنامه‌های مخرب از این قابلیت برای نقض حفاظت موجود در بین کاربران استفاده کنند."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"مجوز کامل برای ارتباط بین کاربران"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوث‌های صوتی"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"صفحه نمایش بی‌سیم"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"برقراری ارتباط با دستگاه"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"فرستادن صفحه نمایش به دستگاه"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"در حال جستجو برای دستگاه‌ها..."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 07a4c6e..ed04c3a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Antaa sovelluksen vastaanottaa ja käsitellä Bluetooth MAP -viestejä. Sovellus voi valvoa ja poistaa laitteeseesi lähetettyjä viestejä näyttämättä niitä sinulle."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"käynnissä olevien sovellusten noutaminen"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Antaa sovelluksen noutaa tietoja käynnissä olevista ja äskettäin suoritetuista tehtävistä. Sovellus voi saada tietoja laitteella käytetyistä sovelluksista."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"suorita käyttäjien välisiä toimintoja"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Antaa sovelluksen suorittaa käyttäjien välisiä toimintoja laitteessa. Haitalliset sovellukset voivat vahingoittaa käyttäjien välistä suojausta."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lupa suorittaa käyttäjien välisiä toimintoja"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Antaa sovelluksen muokata selaimen historiaa ja puhelimeen tallennettuja kirjanmerkkejä. Sovellus voi poistaa tai muokata selaimen tietoja. Huomaa: kolmannen osapuolen selaimet tai muut sovellukset, jotka pystyvät selaamaan verkkoa, eivät saa käyttää tätä lupaa."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"aseta herätys"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Antaa sovelluksen asettaa hälytyksen sisäiseen herätyskellosovellukseen. Jotkin herätyskellosovellukset eivät välttämättä käytä tätä ominaisuutta."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"vastaajaviestien kirjoitus"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Antaa sovelluksen muokata ja poistaa puhelinvastaajaan saapuneita viestejä."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"lisää vastaajaviesti"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Antaa sovelluksen lisätä viestejä saapuneisiin vastaajaviesteihin."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"vastaajaviestien luku"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Antaa sovelluksen lukea vastaajaviestisi."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"selaimen maantieteellisen sijainnin lupien muokkaaminen"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Antaa sovelluksen muokata Selaimen maantieteellisen sijainnin lupia. Haitalliset sovellukset voivat sallia tällä sijaintitietojen lähettämisen mielivaltaisiin sivustoihin."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"vahvista paketteja"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Järjestelmä"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ääni"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Langaton näyttö"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Median äänentoisto"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Yhdistä laitteeseen"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lähetä näyttö laitteeseen"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Etsitään laitteita…"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 19db01a..39a1a9f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permet à l\'application de recevoir et traiter des messages par Bluetooth à l\'aide du profil MAP. Cela signifie que l\'application peut contrôler ou supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"récupérer les données des applications en cours d\'exécution"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permet à l\'application de récupérer des données sur des tâches en cours d\'exécution et récemment exécutées. L\'application est ainsi susceptible d\'obtenir des données concernant les applications utilisées sur l\'appareil."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre les utilisateurs"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet à l\'application d\'effectuer des actions entre les différents utilisateurs de l\'appareil. Les applications malveillantes peuvent utiliser cette autorisation pour passer outre la protection entre les utilisateurs."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"autorisation totale d\'interagir entre les utilisateurs"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permet à l\'application de modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Cette autorisation peut lui permettre d\'effacer ou de modifier les données du navigateur. Remarque : il est possible que cette autorisation ne soit pas appliquée par les navigateurs tiers ni par d\'autres applications permettant de naviguer sur le Web."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"définir une alarme"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permet à l\'application de régler la sonnerie d\'une fonction de réveil installée sur votre appareil. Cette fonctionnalité n\'est pas compatible avec toutes les applications de réveils."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"modifier les messages vocaux"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Autoriser l\'application à modifier et à supprimer des messages de la boîte de réception des messages vocaux."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ajouter des messages vocaux"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permet à l\'application d\'ajouter des messages à votre messagerie vocale."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"accéder aux messages vocaux"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Autoriser l\'application à accéder à vos messages vocaux."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modifier les autorisations de géolocalisation du navigateur"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permet à l\'application de modifier les autorisations de géolocalisation du navigateur. Des applications malveillantes peuvent exploiter cette fonctionnalité pour permettre l\'envoi de données de localisation à des sites Web arbitraires."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"vérifier les paquets"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Diffuser l\'écran sur l\'appareil"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index eea8ad9..e28d70f 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permet à l\'application de recevoir et traiter des messages MAP Bluetooth. Cela signifie que l\'application peut contrôler ou supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"récupérer les applications en cours d\'exécution"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution et récemment exécutées. L\'application est ainsi susceptible d\'obtenir des informations sur les applications utilisées sur l\'appareil."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre les utilisateurs"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet à l\'application d\'effectuer des actions entre les différents utilisateurs de l\'appareil. Les applications malveillantes peuvent utiliser cette autorisation pour passer outre la protection entre les utilisateurs."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"autorisation totale d\'interagir entre les utilisateurs"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permet à l\'application de modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Cette autorisation peut lui permettre d\'effacer ou de modifier les données du navigateur. Remarque : il est possible que cette autorisation ne soit pas appliquée par les navigateurs tiers ni par d\'autres applications permettant de naviguer sur le Web."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"définir une alarme"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permet à l\'application de régler la sonnerie d\'un réveil installé. Cette fonctionnalité n\'est pas disponible sur tous les réveils."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"modifier les messages vocaux"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Autoriser l\'application à modifier et à supprimer des messages de la boîte de réception des messages vocaux"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ajouter un message vocal"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permet à l\'application d\'ajouter des messages à votre messagerie vocale."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"accéder à la messagerie vocale"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Autoriser l\'application à accéder à votre messagerie vocale"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modifier les autorisations de géolocalisation du navigateur"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permet à l\'application de modifier les autorisations de géolocalisation du navigateur. Des applications malveillantes peuvent exploiter cette fonctionnalité pour permettre l\'envoi de données de localisation à des sites Web arbitraires."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"vérifier les packages"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Caster l\'écran sur l\'appareil"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index eb7a45b..6f9e9e7 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que a aplicación reciba e procese as mensaxes de MAP por Bluetooth. Isto quere dicir que a aplicación podería controlar ou eliminar as mensaxes enviadas ao teu dispositivo sen mostrarchas."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicacións en execución"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite á aplicación recuperar información acerca de tarefas que se están executando actualmente ou que se executaron recentemente. É posible que esta acción permita á aplicación descubrir información acerca de que aplicacións se utilizan no dispositivo."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interactuar entre os usuarios"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite á aplicación levar a cabo accións nos diferentes usuarios do dispositivo. É posible que aplicacións maliciosas utilicen isto para vulnerar a protección entre os usuarios."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenza completa para interactuar entre os usuarios"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio por Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualización sen fíos"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída multimedia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar co dispositivo"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emisión de pantalla no dispositivo"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b2665e3..6bf9c70 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ऐप्स को Bluetooth MAP संदेशों को प्राप्त करने और भेजने देती है. इसका अर्थ है कि ऐप्स आपके उपकरण पर भेजे गए संदेशों को आपको दिखाए बिना ही मॉनीटर कर सकता है या उन्हें हटा सकता है."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे ऐप्स पुनर्प्राप्त करें"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ऐप्स  को वर्तमान में और हाल ही में चल रहे कार्यों के बारे में जानकारी को पुन: प्राप्‍त करने देता है. इससे ऐप्स  उपकरण पर उपयोग किए गए ऐप्स  के बारे में जानकारी खोज सकता है."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"उपयोगकर्ताओं के बीच सहभागिता करें"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ऐप्स  को उपकरण पर भिन्न उपयोगकर्ताओं के बीच कार्य निष्पादित करने देता है. दुर्भावनापूर्ण ऐप्स  उपयोगकर्ताओं के बीच सुरक्षा का उल्लंघन करने के लिए इसका उपयोग कर सकते हैं."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"उपयोगकर्ताओं के बीच सहभागिता करने के लिए पूर्ण लाइसेंस"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्‍टम"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस प्रदर्शन"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"उपकरण से कनेक्ट करें"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"स्क्रीन को उपकरण में कास्ट करें"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"उपकरण खोजे जा रहे हैं…"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2883233..a01d72d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Aplikaciji omogućuje primanje i obradu Bluetooth MAP poruka. To znači da aplikacija može nadzirati ili brisati poruke poslane na vaš uređaj, a da vam ih ne prikaže."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"dohvaćanje pokrenutih aplikacija"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Aplikaciji omogućuje dohvaćanje informacija o trenutačnim i nedavnim tekućim zadacima. To aplikaciji može omogućiti otkrivanje informacija o tome koje se aplikacije upotrebljavaju na uređaju."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcija među korisnicima"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Omogućuje aplikaciji izvršavanje radnji među korisnicima na uređaju. Zlonamjerne aplikacije mogu to iskoristiti za narušavanje zaštite među korisnicima."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"dozvola za potpunu interakciju među korisnicima"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sustav"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični prikaz"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezivanje s uređajem"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emitiranje zaslona na uređaj"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Traženje uređaja…"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4dfa0db..68a5dff 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Lehetővé teszi az alkalmazás számára, hogy Bluetooth MAP üzeneteket fogadjon és dolgozzon fel. Ez azt jelenti, hogy az alkalmazás anélkül figyelheti meg vagy törölheti a beérkező üzeneteket, hogy megjelenítené azokat Önnek."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"futó alkalmazások lekérése"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Lehetővé teszi az alkalmazás számára a jelenleg futó és nemrég befejezett feladatokkal kapcsolatos információk lekérését. Ezáltal az alkalmazás engedélyt kap az eszközön használt alkalmazásokkal kapcsolatos információk felderítésére."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"felhasználók közötti interakció"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Lehetővé teszi az alkalmazás számára, hogy több felhasználó között végezzen különféle műveleteket az eszközön. A rosszindulatú alkalmazások arra használhatják ezt, hogy megsértsék a felhasználók biztonságát."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"teljes licenc a felhasználók közötti interakcióhoz"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Rendszer"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Vezeték nélküli kijelző"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Csatlakozás adott eszközhöz"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Képernyő átküldése az eszközre"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Eszközkeresés…"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 942a279..7bf6207 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Թույլ է տալիս հավելվածին ստանալ և մշակել Bluetooth MAP հաղորդագրությունները: Սա նշանակում է, որ հավելվածը կարող է ստուգել կամ ջնջել ձեր սարքին ուղարկված հաղորդագրությունները` առանց դրանք ձեզ ցուցադրելու:"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"առբերել աշխատող հավելվածները"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Թույլ է տալիս հավելվածին առբերել մանրամասն տեղեկություններ առկա և վերջերս աշխատող առաջադրանքների մասին: Սա կարող է թույլ տալ հավելվածին հայտնաբերել անձնական տեղեկություններ այլ հավելվածների վերաբերյալ:"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"հաղորդակցվել օգտվողների միջև"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Թույլ է տալիս հավելվածին իրականացնել գործողություններ սարքի տարբեր օգտվողների միջոցով: Վնասարար հավելվածները կարող են օգտագործել սա` խախտելու օգտվողների միջև պաշտպանությունը:"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ամբողջական հաղորդակցվելու արտոնություն օգտվողների միջև"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Թույլ է տալիս հավելվածին փոփոխել դիտարկչի պատմությունը կամ ձեր հեռախոսում պահված էջանիշերը: Այն կարող է թույլ տալ հավելվածին ջնջել կամ փոփոխել դիտարկչի տվյալները: Նշում. այս թույլտվությունը չի կարող գործածվել կողմնակի դիտարկիչների կամ վեբ զննարկման հնարավորություններով այլ հավելվածների կողմից:"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"դնել ազդանշան"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Թույլ է տալիս հավելվածին սահմանել զարթուցիչի ծրագրում տեղադրված ազդանշանը: Զարթուցիչի որոշ հավելվածներ չեն կարող կիրառել այս հատկությունը:"</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"գրել ձայնային փոստ"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Ծրագրին թույլ է տալիս մուտքի արկղից փոփոխել և հեռացնել ձեր ձայնային փոստը:"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ավելացնել ձայնային փոստ"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Թույլ է տալիս հավելվածին ավելացնել հաղորդագրություններ ձեր ձայնային փոստի արկղում:"</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"հաստատել փաթեթները"</string>
@@ -1390,10 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ծրագրին թույլ է տալիս կապվել վստահելի գործակալի ծառայությանը:"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Փոխազդել թարմացման և վերականգնման համակարգի հետ"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Թույլ է տալիս ծրագրին փոխազդել վերականգնման համակարգի և համակարգի թարմացումների հետ:"</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Ստեղծել մեդիայի տեսարձակման աշխատաշրջաններ"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ծրագրին թույլ է տալիս ստեղծել մեդիայի տեսարձակման աշխատաշրջաններ: Այդ աշխատաշրջանները կարող են ծրագրերին թույլ տալ հավաքագրել էկրանի և աուդիոյի բովանդակությունը: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Հպեք երկու անգամ` դիտափոխման կարգավորման համար"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Չհաջողվեց վիջեթ ավելացնել:"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Առաջ"</string>
@@ -1518,20 +1516,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Խմբագրել"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Տվյալների օգտագործման նախազգուշացում"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Հպեք` օգտագործումը և կարգավորումները տեսնելու համար:"</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G տվյալների կապն անջատված է"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G տվյալների կապն անջատված է"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Բջջային տվյալներն անջատված են"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi տվյալներն անջատված են"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"Սահմանաչափը սպառվեց"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G տվյալների սահմանը գերազանցված է"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G տվյալների սահմանը գերազանցվել է"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Բջջային տվյալների չափը սպառվեց"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi տվյալների սահմանը գերազանցվել է"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g>-ը գերազանցում է նշված սահմանաչափը:"</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Հետնաշերտային տվյալները սահմանափակ են"</string>
@@ -1567,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Համակարգ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի ձայնանյութ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Անլար էկրան"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Մեդիա արտածում"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Միանալ սարքին"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Հեռարձակել էկրանը սարքի վրա"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Որոնվում են սարքեր..."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 327d2ac..a730c8d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Mengizinkan aplikasi menerima dan memproses pesan MAP Bluetooth. Artinya, aplikasi dapat memantau atau menghapus pesan yang dikirim ke perangkat Anda tanpa menunjukkannya kepada Anda."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"mengambil apl yang berjalan"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Memungkinkan aplikasi mengambil informasi tentang tugas yang dijalankan saat ini dan baru-baru ini. Izin ini memungkinkan aplikasi menemukan informasi tentang aplikasi mana yang digunakan pada perangkat."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"berinteraksi antar-pengguna"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Mengizinkan aplikasi melakukan tindakan antar-pengguna yang berbeda pada perangkat. Aplikasi berbahaya dapat menggunakan ini untuk mengganggu perlindungan antar-pengguna."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lisensi penuh untuk berinteraksi antar-pengguna"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Layar nirkabel"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Keluaran media"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambungkan ke perangkat"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmisi layar ke perangkat"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Menelusuri perangkat…"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index c76d4d79..564b4e8 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Leyfir forritinu að taka á móti og vinna úr Bluetooth MAP-skilaboðum. Þetta þýðir að forritið getur fylgst með eða eytt skilaboðum sem send eru í tækið án þess að sýna þér þau."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"sækja forrit í gangi"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Leyfir forriti að sækja upplýsingar um opin forrit og forrit sem nýlega hafa verið opin. Þetta getur gert forritinu kleift að nálgast upplýsingar um forritin sem notuð eru í tækinu."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"samskipti á milli notenda"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Leyfir forriti að framkvæma aðgerðir á milli notenda tækisins. Spilliforrit geta notað þetta til að brjóta á bak aftur vörn á milli notenda."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fullt leyfi til að eiga í samskiptum notenda á milli"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Kerfi"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-hljóð"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Þráðlaus skjábirting"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Margmiðlunarúttak"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Tengjast tæki"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Senda skjá út í tæki"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Leitar að tækjum…"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index bf821f5..8d7a210 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Consente all\'app di ricevere ed elaborare i messaggi Bluetooth MAP. Questo significa che l\'app può monitorare o eliminare i messaggi inviati al tuo dispositivo senza mostrarteli."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"recupero applicazioni in esecuzione"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Consente all\'applicazione di recuperare informazioni sulle attività attualmente e recentemente in esecuzione. Ciò potrebbe consentire all\'applicazione di scoprire informazioni sulle applicazioni in uso sul dispositivo."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interazione tra gli utenti"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Consente all\'applicazione di compiere azioni per diversi utenti sul dispositivo. Le applicazioni dannose potrebbero farne uso per violare la protezione tra utenti."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenza completa per l\'interazione tra utenti"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualizzazione wireless"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Uscita media"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Connetti al dispositivo"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Trasmetti schermo al dispositivo"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ricerca di dispositivi in corso…"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index cba8770..82d9242 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"‏הרשאה זו מאפשרת לאפליקציה לקבל ולעבד הודעות MAP של Bluetooth. משמעות הדבר היא שהאפליקציה יכולה לעקוב אחר הודעות הנשלחות למכשיר שלך או למחוק אותן מבלי להראות לך אותן."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"אחזור אפליקציות פעילות"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"מאפשר לאפליקציה לאחזר מידע לגבי משימות הפועלות כרגע ושפעלו לאחרונה. ייתכן שהדבר יתיר לאפליקציה לגלות מידע לגבי האפליקציות שבהן נעשה שימוש במכשיר."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"אינטראקציה בין משתמשים"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"מאפשר לאפליקציה לבצע פעולות בין משתמשים שונים במכשיר. אפליקציות זדוניות עשויות להשתמש ביכולת זו כדי לפרוץ את ההגנה בין משתמשים."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"רישיון מלא לבצע אינטראקציה בין משתמשים"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"‏מאפשר לאפליקציה לשנות את ההיסטוריה או ה-Bookmarks של הדפדפן המאוחסנים בטלפון. הדבר עשוי לאפשר לאפליקציה למחוק או לשנות נתוני דפדפן. שים לב: אישור זה אינו ניתן לאכיפה על ידי דפדפני צד שלישי או אפליקציות אחרות בעלות יכולות גלישה באינטרנט."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"הגדרת התראה"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"מאפשר לאפליקציה להגדיר התראה באפליקציה מותקנת של שעון מעורר. אפליקציות מסוימות של שעון מעורר אינן מיישמות תכונה זו."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"כתיבת הודעות דואר קולי"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"מאפשרת לאפליקציה לשנות ולהסיר הודעות מתיבת הדואר הנכנס של דואר קולי."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"הוסף דואר קולי"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"מאפשר לאפליקציה להוסיף הודעות לתיבת הדואר הקולי."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"אימות חבילות"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"מערכת"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"‏אודיו Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"צג אלחוטי"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"פלט מדיה"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"התחברות למכשיר"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"העברת מסך אל מכשיר"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"מחפש מכשירים…"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 00be975..aa7774d 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAPメッセージの受信と処理をアプリに許可します。これにより、端末に届いたメッセージをアプリが表示することなく監視または削除するおそれがあります。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"実行中のアプリの取得"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"現在実行中または最近実行したタスクに関する情報の取得をアプリに許可します。これにより、その端末でどのアプリを使用しているかをアプリから識別できるようになる可能性があります。"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ユーザー間の交流"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"端末上の各ユーザーに対して操作を実行することをアプリに許可します。この許可を悪意のあるアプリに利用されると、ユーザー間の保護が侵害される恐れがあります。"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ユーザー間で交流するための完全ライセンス"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ワイヤレスディスプレイ"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"端末に接続"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"端末への画面のキャスト"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"端末を検索しています…"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 86d6e66..cb3f60f 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"აპს შეეძლება Bluetooth MAP შეტყობინებების მიღება და დამუშავება. ეს ნიშნავს, რომ აპს შეეძლება შეტყობინებების მონიტორინგი და მათი წაშლა თქვენთვის ჩვენების გარეშე."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"მოქმედი აპების მოძიება"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"აპს შეეძლება მოიძიოს ინფორმაცია ამჟამად და უახლოეს წარსულში მიმდინარე ამოცანების შესახებ. ამგვარად, აპს აქვს შესაძლებლობა აღმოაჩინოს ინფორმაცია იმის შესახებ, თუ რომელი აპლიკაციებია გამოყენებული მოწყობილობაზე."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"მომხმარებლებს შორის ინტერაქცია"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"აპს შეეძლება, სხვადასხვა მომხმარებლის მოქმედებები შეასრულოს მოწყობილობაზე. მავნე აპებმა შეიძლება მომხმარებლებს შორის დაცვის დასარღვევად გამოიყენონ."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"მომხმარებლებთან ინტერაქციის სრული ლიცენზია"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"აპს შეეძლება, შეცვალოს ბრაუზერის ისტორია და თქვენ ტელეფონში შენახული სანიშნეები. ამან შეიძლება უფლება მისცეს აპს, წაშალოს ან შეცვალოს ბრაუზერის მონაცემები. შენიშვნა: ეს ნებართვა არ შეიძლება შესრულდეს მესამე მხარის ბრაუზერების ან ვებ დათვალიერების შესაძლებლობის მქონე სხვა აპლიკაციების მიერ."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"მაღვიძარას დაყენება"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"აპს შეეძლება მაღვიძარას დაყენება დაინსტალირებული მაღვიძარას აპლიკაციაში. ამ ფუნქციას მაღვიძარას ზოგიერთი აპი არ იყენებს."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"ხმოვანი ფოსტის ჩათვლით"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ნებას რთავს ამ აპს, შეცვალოს და ამოშალოს შეტყობინებები თქვენი ხმოვანი ფოსტის შემოსულებიდან."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ხმოვანი ფოსტის დამატება"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"აპს შეეძლება დაამატოს შეტყობინებები თქვენი ხმოვანი ფოსტის შემოსულებში."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"პაკეტების გადამოწმება"</string>
@@ -1295,7 +1295,7 @@
     <string name="sim_removed_message" msgid="5450336489923274918">"ფიჭური კავშირი არ იქნება ხელმისაწვდომი, ვიდრე არ ჩადებთ ქმედით SIM ბარათს და გადატვირთავთ."</string>
     <string name="sim_done_button" msgid="827949989369963775">"დასრულდა"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"SIM ბარათი დაემატა"</string>
-    <string name="sim_added_message" msgid="7797975656153714319">"გადატვირთთ თქვენი მოწყობილობა ფიჭურ ქსელზე წვდომისთვის."</string>
+    <string name="sim_added_message" msgid="7797975656153714319">"გადატვირთეთ თქვენი მოწყობილობა ფიჭურ ქსელზე წვდომისთვის."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"გადატვირთვა"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"დროის დაყენება"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"თარიღის დაყენება"</string>
@@ -1390,10 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"საშუალებას აძლევს აპლიკაციას მიემაგროს სანდო აგენტის სერვისს."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"განახლებასთან და აღდგენის სისტემასთან ინტერაქცია"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"საშუალებას აძლევს აპლიკაციას მოახდინოს აღდგენის სისტემასთან და სისტემის განახლებასთან ინტერაქცია."</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"მედია პროეცირების სესიების შექმნა"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"საშუალებას აძლევს აპლიკაციას, შექმნას მედია პროეცირების სესიები. ამ სესიებმა შესაძლოა მისცეს აპლიკაციებს საშუალება, აღიბეჭდოს ეკრანისა და აუდიოს კონტენტი. ჩვეულებრივ აპს წესით ეს არასოდეს არ უნდა დასჭირდეს."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"მასშტაბის მართვისთვის შეეხეთ ორჯერ."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ვერ დაემატა ვიჯეტი."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"გადასვლა"</string>
@@ -1518,20 +1516,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"რედაქტირება"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"ინტერნეტის გამოყენების გაფრთხილება"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"შეეხეთ მოხმარებისა და პარამეტრების სანახავად."</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G მონაც. გადაცემა გამორთულია"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G მონაც. გადაცემა გამორთულია"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"ფიჭური ინტერნეტი გამორთულია"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi მონაც. გადაცემა გამორთულია"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"ლიმიტი მიღწეულია"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"გადაჭარბებულია 2G-3G მონაცემების ლიმიტი"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G ლიმიტი გადაჭარბებულია"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"ფიჭ. ინტერნეტის ლიმიტი მიღწეულია"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi‑Fi მონაცემთა ლიმიტი გადაჭარბებულია"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"ლიმიტი გადაჭარბებულია <xliff:g id="SIZE">%s</xliff:g>-ით."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"მონაცემთა ფონური გადაცემა შეზღუდულია"</string>
@@ -1567,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"სისტემა"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth აუდიო"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"უსადენო ეკრანი"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"მედია გამომავალი"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"მოწყობილობასთან დაკავშირება"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ეკრანის მოწყობილობაზე გადაცემა"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"მოწყობილობების ძიება…"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index dd24dcf..172e45a 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Қолданбаға Bluetooth MAP хабарларын алуға және өңдеуге рұқсат береді. Бұл қолданба құрылғыңызға жіберілген хабарларды сізге көрсетпестен бақылауы немесе жоюы мүмкін екенін білдіреді."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"жұмыс істеп жатқан қолданбаларды шығарып алу"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Қолданбаларға ағымдағы және соңғы тапсырмалар туралы ақпарат алу мүмкіндігін береді. Бұл қолданбаға құрылғы қолданатын басқа қолданбалар туралы деректері анықтау мүмкіндігін беруі ықтимал."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"барлық пайдаланушылармен қарым-қатынас жасау"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Қолданбаға құрылғыдағы әртүрлі пайдаланушылар арасында әрекеттер орындау мүмкіндігін береді. Залалды қолданбалар бұны пайдаланушылар арасындағы қорғанысты бұзу үшін пайдалануы мүмкін."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"барлық пайдаланушылармен қарым-қатынас жасау лицензиясы"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Қолданбаларға телефонда сақталған Браузер кіріп шыққан барлық URL тарихын және Браузер бетбелгілерін өзгерту мүмкіндігін береді. Есіңізде болсын: бұл рұқсатты үшінші жақ браузерлері немесе веб шолу қабілеті бар басқа қолданбалар қолданбауы мүмкін."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"дабылды орнату"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Қолданбаға орнатылған оятқыш қолданбасында дабылды орнатуға рұқсат береді. Кейбір қолданбаларда бұл мүмкіндік іске асырылмауы мүмкін."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"дауыстық хабарлар жазу"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Қолданбаға дауыстық поштаңыздың «Кіріс» қалтасындағы хабарларды өзгертуге және жоюға рұқсат етеді."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"дауыс хабарын қосу"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Қолданбаға дауыстық поштаңыздың «Кіріс» қалтасына хабарлар қосуға рұқсат береді."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"жинақтарды растау"</string>
@@ -1390,10 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Қолданбаға сенімді агент қызметіне байластыруға рұқсат береді."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Жаңарту және қалпына келтіру жүйелерімен қатынасу"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Қолданбаның қалпына келтіру жүйесімен және жүйе жаңартуларымен қатынасу мүмкіндігін береді."</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Тасушыны проекциялау сеанстарын жасау"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Қолданбаға тасушыны проекциялау сеанстарын жасауға рұқсат етеді. Бұл сеанстар қолданбаларға дисплей және аудио мазмұнын түсіру мүмкіндігін қамтамасыз етеді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Масштабтауды басқару үшін екі рет түртіңіз"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетті қосу."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Өту"</string>
@@ -1518,20 +1516,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгерту"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Дерекқор қолдануға қатысты ескерту"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Қолданыс және параметрлерді көру үшін түртіңіз."</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G деректері өшірулі"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G деректері өшірулі"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Ұялы деректер өшірулі"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi деректері өшірулі"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"Шекке жеттіңіз"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2Г-3Г дерекқор шектеуінен асып кетті"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4Ш дерекқор шектеуінен асып кетті"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Ұялы деректер шегі асырылды"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi дерекқор шектеуінен асып кетті"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Анықталған уақтыттан <xliff:g id="SIZE">%s</xliff:g> асты."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Тарихы туралы дерекқор шектелген"</string>
@@ -1567,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Жүйе"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth aудио"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Сымсыз дисплей"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Meдиа шығысы"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Құрылғыға жалғау"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Экранды құрылғымен байланыстыру"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Құрылғыларды іздеуде…"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index ba6c0ac..7b2c26c 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ឲ្យ​កម្មវិធី​ទទួល និង​ដំណើរការ​សារ MAP ប៊្លូធូស។ មាន​ន័យ​ថា កម្មវិធី​អាច​តាមដាន​ ឬ​លុប​សារ​ដែល​បាន​ផ្ញើ​ទៅ​ឧបករណ៍​របស់​អ្នក​ដោយ​​មិន​បង្ហាញ​ពួកវា​ដល់​អ្នក។"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"ទៅ​យក​កម្មវិធី​កំពុង​ដំណើរការ"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ឲ្យ​កម្មវិធី​ទៅ​យក​ព័ត៌មាន​លម្អិត​អំពី​កិច្ចការ​ដែល​កំពុង​ដំណើរការ​បច្ចុប្បន្ន។ វា​អាច​ឲ្យ​កម្មវិធី​រកមើល​ព័ត៌មាន​ថា​តើ​កម្មវិធី​ណាមួយ​ត្រូវ​បាន​ប្រើ​លើ​ឧបករណ៍។"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"អន្តរកម្ម​តាម​​អ្នក​ប្រើ"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ឲ្យ​កម្មវិធី​អនុវត្ត​សកម្មភាព​ឆ្លង​អ្នកប្រើ​ផ្សេងៗ​​លើ​ឧបករណ៍។ កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា ដើម្បី​បំពាន​ការ​ការពារ​រវាង​អ្នក​ប្រើ។"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"អាជ្ញាប័ណ្ណ​ពេញលេញ​ ដើម្បី​ទាក់ទង​អ្នក​ប្រើ"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ឲ្យ​កម្មវិធី​កែ​ប្រវត្តិ ឬ​ចំណាំ​របស់​កម្មវិធី​អ៊ីនធឺណិត​ដែល​បាន​រក្សាទុក​ក្នុង​ទូរស័ព្ទ​​របស់​អ្នក។ កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា​ដើម្បី​លុប ឬ​កែ​ទិន្នន័យ​នៃ​កម្មវិធី​អ៊ីនធឺណិត​របស់​អ្នក។ ចំណាំ៖ សិទ្ធិ​នេះ​អាច​ត្រូវ​បាន​បង្ខំ​ដោយ​កម្មវិធី​អ៊ីនធឺណិត​​ភាគី​ទីបី​ ឬ​​កម្មវិធី​ផ្សេង​ដែល​មាន​សមត្ថភាព​រុករក​បណ្ដាញ។ស"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"កំណត់​សំឡេង​រោទ៍"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"ឲ្យ​កម្មវិធី​កំណត់​​សំឡេង​រោទ៍​ក្នុង​កម្មវិធី​នាឡិកា​រោទ៍​បាន​ដំឡើង។​ កម្មវិធី​នាឡិកា​រោទ៍​មួយ​ចំនួន​អាច​មិន​អនុវត្ត​លក្ខណៈ​នេះ។"</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"សរសេរ​សារ​ជា​សំឡេង"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ឲ្យ​កម្មវិធី​កែប្រែ​ និង​លុប​សារ​ចេញពី​ប្រអប់​ទទួល​សារ​ជា​សំឡេង​របស់​អ្នក។"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"បន្ថែម​សារ​ជា​សំឡេង"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ឲ្យ​កម្មវិធី​បន្ថែម​សារ​ទៅ​ប្រអប់​ទទួល​សារ​ជា​សំឡេង​របស់​អ្នក។"</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"ផ្ទៀងផ្ទាត់​កញ្ចប់"</string>
@@ -1561,7 +1561,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ប្រព័ន្ធ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"សំឡេង​ប៊្លូធូស"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"បង្ហាញ​បណ្ដាញ​ឥត​ខ្សែ"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"លទ្ធផល​មេឌៀ"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"ភ្ជាប់​ឧបករណ៍"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ចាត់​ថ្នាក់​អេក្រង់​ទៅ​ឧបករណ៍"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"កំពុង​ស្វែងរក​ឧបករណ៍..."</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index d6143e1..cedab61 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ಬ್ಲೂಟೂಟ್ MAP ಸಂದೇಶಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಮತ್ತು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಇದರರ್ಥ, ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಕಳುಹಿಸಲಾಗಿರುವ ಸಂದೇಶಗಳನ್ನು ನಿಮಗೆ ತೋರಿಸದೆಯೇ, ಅಪ್ಲಿಕೇಶನ್ ಅವುಗಳನ್ನು ಮಾನಿಟರ್ ಮಾಡಬಹುದು ಅಥವಾ ಅಳಿಸಬಹುದು."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"ರನ್‌ ಆಗುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಹಿಂಪಡೆಯಿರಿ"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ಪ್ರಸ್ತುತವಿರುವ ಮತ್ತು ಇತ್ತೀಚಿಗೆ ಚಾಲ್ತಿಯಾಗಿರುವ ಕಾರ್ಯಗಳ ಕುರಿತ ಮಾಹಿತಿಯನ್ನು ಮರುಪಡೆದುಕೊಳ್ಳಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಇದು ಸಾಧನದಲ್ಲಿ ಯಾವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬಳಸಲಾಗಿದೆ ಎಂಬುದರ ಕುರಿತ ಮಾಹಿತಿಯನ್ನು ಅನ್ವೇಷಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸಬಹುದು."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ಬಳಕೆದಾರರ ಜೊತೆ ಸಂವಹನ ನಡೆಸಿ"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ಸಾಧನದಲ್ಲಿರುವ ವಿವಿಧ ಬಳಕೆದಾರರಾದ್ಯಂತ ಕ್ರಿಯೆಗಳನ್ನು ನಿರ್ವಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‍‍ಗಳು ಇದನ್ನು ಬಳಕೆದಾರರ ನಡುವಿನ ರಕ್ಷಣೆಯನ್ನು ಉಲ್ಲಂಘಿಸಲು ಬಳಸಿಕೊಳ್ಳಬಹುದು."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ಬಳಕೆದಾರರ ಜೊತೆಗೆ ಸಂವಹನ ನಡೆಸಲು ಪೂರ್ಣ ಪರವಾನಗಿ"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ಸಿಸ್ಟಂ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ವಯರ್‌ಲೆಸ್ ಪ್ರದರ್ಶನ"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"ಮೀಡಿಯಾ ಔಟ್‌ಪುಟ್"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಿ"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ಸಾಧನಕ್ಕೆ ಬಿತ್ತರಿಸುವ ಪರದೆ"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 7b9c05a..8154700 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"앱이 블루투스 MAP 메시지를 수신하고 처리하도록 허용합니다. 이는 앱이 나에게 보여주지 않고 내 기기에 전송된 메시지를 모니터링하거나 삭제할 수 있음을 의미합니다."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"실행 중인 앱 검색"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"앱이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 허용합니다. 이 경우 앱이 기기에서 사용되는 다른 앱에 대한 정보를 검색할 수 있습니다."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"여러 사용자와의 상호작용"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"앱이 기기에서 다양한 사용자에 대한 작업을 수행할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자 간의 보호를 위반할 수 있습니다."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"여러 사용자와의 상호작용을 위한 정식 라이선스"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"앱이 휴대전화에 저장된 브라우저 기록 또는 북마크를 수정할 수 있도록 허용합니다. 이 경우 앱이 브라우저 데이터를 삭제 또는 수정할 수 있습니다. 참고: 이 권한은 타사 브라우저 또는 브라우저 기능을 가진 기타 애플리케이션에 적용되지 않습니다."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"알람 설정"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"앱이 설치된 알람 시계 앱에서 알람을 설정할 수 있도록 허용합니다. 일부 알람 시계 앱에는 이 기능이 구현되지 않을 수 있습니다."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"음성사서함 쓰기"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"앱이 음성사서함에서 메시지를 수정하고 삭제하도록 허용합니다."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"음성사서함 추가"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"앱이 음성사서함에 메시지를 추가할 수 있도록 허용합니다."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"패키지 확인"</string>
@@ -1391,7 +1391,7 @@
     <string name="permlab_recovery" msgid="3157024487744125846">"업데이트 및 복구 시스템과 상호작용"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"애플리케이션이 복구 시스템 및 시스템 업데이트와 상호작용할 수 있도록 허용합니다."</string>
     <string name="permlab_createMediaProjection" msgid="4941338725487978112">"미디어 프로젝션 세션 만들기"</string>
-    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"애플리케이션이 미디어 프로젝션 세션을 만드는 것을 허용합니다. 이 세션은 애플리케이션에 디스플레이 및 오디오 컨텐츠를 캡처하는 기능을 제공할 수 있습니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"애플리케이션이 미디어 프로젝션 세션을 만드는 것을 허용합니다. 이 세션은 애플리케이션에 디스플레이 및 오디오 콘텐츠를 캡처하는 기능을 제공할 수 있습니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"확대/축소하려면 두 번 터치하세요."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"위젯을 추가할 수 없습니다."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"이동"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"무선 디스플레이"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"기기에 연결"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"기기로 화면 전송"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"기기 검색 중…"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 2ab9816..7a1c96b 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -430,6 +430,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Колдонмого Bluetooth MAP билдирүүлөрүн алуу жана иштеп чыгуу мүмкүнчүлүгүн берет. Демек, колдонмо түзмөгүңүздөгү билдирүүлөрдү сизге көрсөтпөстөн тескеп же жок кыла алат."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"иштеп жаткан колдонмолорду түшүрүп алуу"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Колдонмого учурдагы жана акыркы убакытта пайдаланылган колдонмолор тууралуу  маалымат алууга уруксат берет. Бул колдонмого түзмөктө кандай колдонмолор колдонулаарын билип алууга жол бериши мүмкүн."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"колдонуучулар менен иштешүү"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Колдонмого түзмөктөгү ар кандай колдонуучулардын атынан кыймыл-аракеттерди жүргүзүү уруксатын берет. Зыяндуу колдонмолор, муну менен колдонуучулар аарсындагы коргонду бузуп салышы мүмкүн."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"колдонуучулар менен иштешүү үчүн толук лицензия"</string>
@@ -1340,16 +1344,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Колдонмого телефонуңузда сакталган Серепчинин тарыхын жана Серепчинин бүктөмөлөрүн өзгөртүү уруксатын берет. Бул колдонмого Серепчинин берилиштерин өчүрүү же өзгөртүү уруксатын берет. Эскертүү: бул уруксат үчүнчү тараптык интернет-серепчилерге, же интернетке кирүү мүмкүнчүлүгү бар колдонмолорго таасир этпеши мүмкүн."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"ойготкуч коюу"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Колдонмого ойготкуч саат колдонмосуна үн ишаратын коюу мүмкүнчүлүгүн берет. Айрым ойготкуч саат колдонмолорунда бул мүмкүнчүлүк иштебеши мүмкүн."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"үн почталарын жазуу"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Колдонмонун үн почтаңыздын кирүү кутусунан билдирүүлөрдү өзгөртүп жана алып салуусуна жол ачат."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"үнкат кошуу"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Колдонмого үн почтаңыздын кирүү кутусуна билдирүүлөрдү кошуу мүмкүнчүлүгүн берет."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"таңгактарды текшерүү"</string>
@@ -1809,10 +1809,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Колдонмого ишенимдүү агент кызматына жалгашууга мүмкүнчүлүк берет."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Калыбына келтирүү системасы жана жаңыртуулар менен иштөө"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Колдонмого калыбына келтирүү системасы жана система жаңыртуулары менен карым-катнашуу мүмкүнчүлүгүн берет."</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Медиа чагылдыруу сеанстарын түзүү"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Колдонмого медиа чагылдыруу сеанстарын түзүү мүмкүнчүлүгүн берет. Мындай сеанстардын жардамы менен, колдонмолор дисплей жана видео мазмунду сүрөткө тартып турушат. Кадимки колдонмолор үчүн талап кылынбайт."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Чен өлчөмүн көзөмөлдөө үчүн эки жолу тийип коюңуз"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетти кошуу мүмкүн болбоду."</string>
     <!-- no translation found for ime_action_go (8320845651737369027) -->
@@ -1986,20 +1984,14 @@
     <!-- no translation found for data_usage_warning_title (1955638862122232342) -->
     <skip />
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Колдонууну көрүш үчүн басыңыз."</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2Гб-3Гб көлмдөгү дайындр өчүрлдү."</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4Гб көлөмдөгү дайындар өчүрүлдү"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Уюктук дайындар тармагы өчүк"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi дайындар тармагы өчүк"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"Белгиленген чекке жеттиңиз"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G трафик чектен ашты"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G трафик чектен ашты"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Уюкт дайндр белглнгн чегнн аштңз"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi трафик чегинен ашты"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Орнотулган чектөөдөн <xliff:g id="SIZE">%s</xliff:g> ашты."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Фондук трафик чектелген"</string>
@@ -2049,7 +2041,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Зымсыз дисплей"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Медиа чыгаруу"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Түзмөккө туташуу"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Сырткы экранга чыгаруу"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Түзмөктөр изделүүдө..."</string>
diff --git a/core/res/res/values-large/themes_material.xml b/core/res/res/values-large/themes_material.xml
index 2781608..05fee6b 100644
--- a/core/res/res/values-large/themes_material.xml
+++ b/core/res/res/values-large/themes_material.xml
@@ -35,6 +35,10 @@
     <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Dialog.NoActionBar.FixedSize">
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
-    <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light.Dialog.FixedSize" />
-    <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
+    <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light.Dialog.FixedSize">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+    <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.Dialog.NoActionBar.FixedSize">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
 </resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 22404ff..7b9c218 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ສາ​ມາດ​ຮັບ​ແລະ​ສົ່ງ​ຂໍ້​ຄວາມ Bluetooth MAP ໄດ້. ນີ້​ໝາຍ​ຄວາມ​ວ່າ​ແອັບຯ​ຈະ​ສາ​ມາດ​ກວດ​ເບິ່ງ ຫຼື​ລຶບ​ຂໍ້​ຄວາມ​ທີ່​ສົ່ງ​ຫາ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ໄດ້​ໂດຍ​ບໍ່​ສະ​ແດງ​ຂໍ້​ຄວາມ​ເຫຼົ່າ​ນັ້ນໃຫ້​ທ່ານ​ເຫັນ."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"ດຶງແອັບຯທີ່ເຮັດວຽກຢູ່ມາ"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນກ່ຽວກັບການເຮັດວຽກໃນປັດຈຸບັນ ແລະຫາກໍຜ່ານມາ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຄົ້ນພົບຂໍ້ມູນ ກ່ຽວກັບແອັບພລິເຄຊັນທີ່ໃຊ້ຢູ່ໃນອຸປະກອນໄດ້."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ການຕອບໂຕ້ລະຫວ່າງຜູ່ໃຊ້"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ອະນຸຍາດໃຫ້ແອັບຯດຳເນີນການ ສັ່ງງານຜ່ານຜູ່ໃຊ້ອື່ນໆໃນອຸປະກອນ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດໃຊ້ຄວາມສາມາດນີ້ ເພື່ອລະເມີດການປ້ອງກັນລະຫວ່າງຜູ່ໃຊ້."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ໃບອະນຸຍາດສະບັບເຕັມໃນການໂຕ້ຕອບລະຫວ່າງຜູ່ໃຊ້"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ລະບົບ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ສຽງ Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ການສະແດງຜົນໄຮ້ສາຍ"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"ມີເດຍເອົ້າພຸດ"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"ເຊື່ອມຕໍ່ຫາອຸປະກອນ"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ສົ່ງພາບໜ້າຈໍໄປຫາອຸປະກອນ"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"ກຳລັງຊອກຫາອຸປະກອນ..."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 5eb55c1..61dcf86 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Programai leidžiama gauti ir apdoroti „Bluetooth“ MAP pranešimus. Tai reiškia, kad programa gali stebėti ir ištrinti į jūsų įrenginį siunčiamus pranešimus jums jų neparodžiusi."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"nuskaityti vykdomas programas"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Leidžiama programai nuskaityti informaciją apie šiuo ir pastaruoju metu vykdomas užduotis. Taip programa gali atrasti informacijos, kokios programos naudojamos įrenginyje."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"sąveikauti su naudotojais"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Leidžiama programai atlikti veiksmus skirtingų įrenginio naudotojų profiliuose. Kenkėjiškos programos gali pasinaudoti šiuo leidimu, kad pažeistų naudotojų saugumą."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"visa licencija, leidžianti sąveikauti su naudotojais"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Belaidis rodymas"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Prijungimas prie įrenginio"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Perduoti ekraną į įrenginį"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ieškoma įrenginių…"</string>
@@ -1743,7 +1748,7 @@
     <string name="lock_to_app_toast" msgid="2126866321272822564">"Įjungėte programos užrakinimo funkcijos režimą. Kad išeitumėte, palieskite ir palaikykite mygtuką „Naujausios“"</string>
     <string name="lock_to_app_toast_locked" msgid="4229650395479263497">"Įjungėte programos užrakinimo funkcijos režimą."</string>
     <string name="lock_to_app_title" msgid="5895142291937470019">"Naudoti programos užrakinimo funkciją?"</string>
-    <string name="lock_to_app_description" msgid="2800403592608529611">"Naudojant programos užrakinimo funkciją ekrane užrakinama viena programa.\n\nKad išeitumėte, palieskite ir palaikykite mygtuką „Naujausios“"</string>
+    <string name="lock_to_app_description" msgid="2800403592608529611">"Naudojant programos užrakinimo funkciją ekrane užrakinama viena programa.\n\nKad išeitumėte, palieskite ir palaikykite mygtuką „Naujausios“."</string>
     <string name="lock_to_app_negative" msgid="2259143719362732728">"NE, AČIŪ"</string>
     <string name="lock_to_app_positive" msgid="7085139175671313864">"ĮJUNGTI"</string>
     <string name="lock_to_app_start" msgid="3074665051586318340">"Naudojama programos užrakinimo funkcija"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f005960..e4cd1fe 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Ļauj lietotnei saņemt un apstrādāt Bluetooth MAP ziņojumus. Tas nozīmē, ka lietotne var pārraudzīt vai dzēst uz jūsu ierīci nosūtītos ziņojumus, neparādot tos jums."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"izgūt izmantotās lietotnes"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Ļauj lietotnei izgūt informāciju par pašreiz un nesen darbinātajiem uzdevumiem. Tādējādi lietotne var atklāt informāciju par ierīcē izmantotajām lietojumprogrammām."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"darboties visos lietotāju kontos"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ļauj lietotnei veikt darbības vairāku ierīces lietotāju kontos. Ļaunprātīgas lietotnes var izmantot šo atļauju, lai apdraudētu lietotāju kontu drošību."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"pilna licence ar atļauju darboties visos lietotāju kontos"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistēma"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezvadu attēlošana"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Savienojuma izveide ar ierīci"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekrāna apraide uz ierīci"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Notiek ierīču meklēšana…"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index d49a824..0e54fe5 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Овозможува апликацијата да прима и да обработува пораки МАП преку Bluetooth. Тоа значи дека апликацијата може да следи или да брише пораки испратени до вашиот уред без да ви ги прикаже вам."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"обнови активни апликации"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Овозможува апликацијата да поврати информации за тековно и до неодамна активни задачи. Ова може да овозможи апликацијата да открие информации за тоа кои апликации се користат на уредот."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"комуницирај со корисници"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Овозможува апликацијата да врши дејства кај различни корисници на уредот. Злонамерните апликации може да го искористат тоа да ја нарушат заштитата меѓу корисниците."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"целосна дозвола за комуникација меѓу корисници"</string>
@@ -1557,7 +1561,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудио на Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен приказ"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Излез за медиуми"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Поврзи се со уред"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Префрли екран на уред"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Пребарување за уреди..."</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 9115ba2..f994247 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP സന്ദേശങ്ങൾ സ്വീകരിക്കുന്നതിനും പ്രോസസ്സുചെയ്യുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉപകരണത്തിലേക്ക് അയച്ച സന്ദേശങ്ങൾ നിങ്ങളെ കാണിക്കാതെ തന്നെ നിരീക്ഷിക്കാനോ ഇല്ലാതാക്കാനോ അപ്ലിക്കേഷനാവും."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"പ്രവർത്തിക്കുന്ന അപ്ലിക്കേഷനുകൾ വീണ്ടെടുക്കുക"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"നിലവിലും സമീപകാലത്തും പ്രവർത്തിക്കുന്ന ടാസ്‌ക്കുകളെക്കുറിച്ചുള്ള വവിവരങ്ങൾ വീണ്ടെടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് ഉപകരണത്തിൽ ഉപയോഗിച്ച അപ്ലിക്കേഷനുകളെക്കുറിച്ചുള്ള വിവരം കണ്ടെത്താൻ അപ്ലിക്കേഷനെ അനുവദിക്കാനിടയുണ്ട്."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"എല്ലാ ഉപയോക്താക്കളുമായും സംവദിക്കുക"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ഉപകരണത്തിലെ വ്യത്യസ്‌ത ഉപയോക്താക്കളിലുടനീളം പ്രവർത്തനങ്ങൾ നടത്താൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ ഉപയോക്താക്കൾക്കിടയിലുള്ള പരിരക്ഷ ലംഘിക്കാൻ ഇത് ഉപയോഗിക്കാനിടയുണ്ട്."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"എല്ലാ ഉപയോക്താക്കളുമായും സംവദിക്കാനുള്ള പൂർണ്ണ ലൈസൻസ്"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"സിസ്റ്റം"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ഓഡിയോ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"വയർലെസ് ഡിസ്‌പ്ലേ"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"മീഡിയ ഔട്ട്പുട്ട്"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"ഉപകരണത്തിലേക്ക് കണക്റ്റുചെയ്യുക"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"സ്‌ക്രീൻ ഉപകരണത്തിലേക്ക് കാസ്റ്റുചെയ്യുക"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"ഉപകരണങ്ങൾക്കായി തിരയുന്നു…"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index ea33e8c..e5334a5 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -298,6 +298,8 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Апп нь Блютүүт MAP мессежийг хүлээн авах болон гүйцэтгэх боломжтой. Ингэснээр апп нь таны төхөөрөмжрүү илгээсэн мессежийг танд үзүүлэхгүйгээр хянах болон устгаж чадна."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"ажиллаж байгаа апп-г дуудах"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Апп нь одоо ажиллаж байгаа болон сүүлд ажилласан даалгаврын талаарх мэдээллийг авах боломжтой. Ингэснээр апп нь төхөөмж дээрх ямар аппликешнүүд ашиглагдсан талаарх мэдээлийг олох боломжтой."</string>
+    <string name="permlab_startTasksFromRecents" msgid="8990073877885690623">"саяхных дотроос ажил эхлүүлэх"</string>
+    <string name="permdesc_startTasksFromRecents" msgid="7382133554871222235">"Апп-д ActivityManager.getRecentTaskList()-с буцаж ирсэн дууссан ажлыг эхлүүлэхийн тулд ActivityManager.RecentTaskInfo объектыг ашиглах боломж олгоно."</string>
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"хэрэглэгчидтэй харилцан үйлчлэлцэх"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Апп нь төхөөрөмж дээрх ялгаатай хэрэглэгчдэд үйлдэл гүйцэтгэх боломжтой. Хортой апп нь энийг ашиглан хэрэглэгч хоорондын хамгаалалтыг зөрчих боломжтой."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"хэрэглэгчидтэй харилцан үйлчлэлцэх бүрэн зөвшөөрөл"</string>
@@ -1555,7 +1557,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Блютүүт аудио"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Утасгүй дэлгэц"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Медиа гаралт"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Төхөөрөмжтэй холбох"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Дэлгэцийг төхөөрөмж рүү дамжуулах"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Төхөөрөмжүүдийг хайж байна…"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 30e0efb..788d8b6 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth नकाशा संदेश प्राप्त करण्यास आणि त्यावर प्रक्रिया करण्यास अॅप ला अनुमती देते. याचा अर्थ अॅप आपल्या डिव्हाइसवर पाठविलेले संदेश आपल्याला न दर्शवता त्यांचे परीक्षण करू किंवा ते हटवू शकतो."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"चालणारे अॅप्स पुनर्प्राप्त करा"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"सध्या आणि अलीकडे चालणार्‍या कार्यांविषयी माहिती पुनर्प्राप्त करण्यासाठी अॅप ला अनुमती देते. हे डिव्हाइसवर कोणते अनुप्रयोग वापरले जात आहेत त्याविषयी माहिती शोधण्यासाठी अॅप ला अनुमती देऊ शकतात."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"वापरकर्त्यांशी परस्परसंवाद साधा"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"डिव्हाइसवरील भिन्न वापरकर्त्यांवर कारवाई करण्यासाठी अॅप ला अनुमती देते. दुर्भावनापूर्ण अॅप्स वापरकर्त्यांमधील संरक्षणाचे उल्लंघन करण्यासाठी हे वापरू शकतात."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"वापरकर्त्यांशी परस्परसंवाद साधण्यासाठी पूर्ण परवाना"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्टम"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडिओ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस प्रदर्शन"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"माध्यम आउटपुट"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"डिव्हाइसला कनेक्ट करा"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"डिव्‍हाइसवर स्क्रीन कास्‍ट करा"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"डिव्‍हाइसेस शोधत आहे…"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index fc823ee..419c9b5 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Membenarkan apl menerima dan memproses mesej MAP Bluetooth. Ini bermakna apl boleh memantau atau memadam mesej yang dihantar ke peranti anda tanpa menunjukkannya kepada anda."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"dapatkan semula apl yang sedang dijalankan"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Membenarkan apl mengambil maklumat tentang tugasan yang sedang dan baru berjalan. Ini boleh membenarkan apl untuk menemui maklumat tentang apl mana yang digunakan pada peranti."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"berinteraksi sesama pengguna"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Membenarkan apl melakukan tindakan merentasi pengguna berbeza pada peranti. Apl hasad boleh menggunakan ini untuk melanggar perlindungan antara pengguna."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lesen penuh untuk berinteraksi sesama pengguna"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Membenarkan apl mengubah suai sejarah atau penanda halaman Penyemak Imbas yang tersimpan pada telefon anda. Ini boleh membenarkan apl untuk memadam atau mengubah suai data Penyemak Imbas. Nota: kebenaran ini tidak boleh dikuatkuasakan oleh penyemak imbas pihak ketiga atau aplikasi lain dengan keupayaan menyemak imbas web."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"tetapkan penggera"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Membenarkan apl untuk menetapkan penggera dalam apl penggera jam yang dipasang. Sesetengah applikasi jam penggera tidak boleh melaksanakan ciri ini."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"tulis mel suara"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Membenarkan apl mengubah suai dan mengalih keluar mesej dari peti masuk mel suara anda."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"tambah mel suara"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Membenarkan apl untuk menambahkan mesej pada peti masuk mel suara anda."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"baca mel suara"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Membenarkan apl membaca mel suara anda."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ubah suai kebenaran geolokasi Penyemak Imbas"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Membenarkan apl untuk mengubah suai kebenaran geolokasi Penyemak Imbas. Apl hasad boleh menggunakannya untuk membenarkan menghantar maklumat lokasi kepada laman web sembarangan."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"sahkan pakej"</string>
@@ -1390,10 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Membenarkan aplikasi terikat kepada perkhidmatan ejen amanah."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan kemas kini dan sistem pemulihan"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Membenarkan aplikasi berinteraksi dengan sistem pemulihan dan kemas kini sistem."</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Buat sesi unjuran media"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Membenarkan aplikasi membuat sesi unjuran media. Sesi ini boleh memberikan aplikasi keupayaan untuk mengabadikan paparan dan kandungan audio. Tidak sekali-kali diperlukan oleh apl biasa."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mendapatkan kawalan zum"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Tidak dapat menambahkan widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Pergi"</string>
@@ -1518,20 +1516,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Amaran penggunaan data"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Sentuh untuk melihat penggunaan dan tetapan."</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Data 2G-3G dimatikan"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Data 4G dimatikan"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Data selular dimatikan"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Data Wi-Fi dimatikan"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"Sudah mencapai had"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Melebihi had data 2G-3G"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Melebihi had data 4G"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Melebihi had data seluluar"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Melebihi had data Wi-Fi"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> melebihi had yang ditentukan."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Data latar belakang terhad"</string>
@@ -1567,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Paparan wayarles"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambung ke peranti"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Hantar skrin ke peranti"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Mencari peranti..."</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 46b536a..24be03d 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP စာများကို app မှလက်ခံကာ အလုပ်လုပ်ရန် ခွင့်ပြင်မည်။ ဆိုလိုသည်မှာ app သည်သင့်အား မပြသဘဲ သင့်ကိရိယာသို့ပို့လိုက်သည့် စာများကို ထိန်းချုပ်နိုင် သို့မဟုတ် ဖျက်နိုင်ပါသည်။"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"အလုပ်လုပ်နေကြသည့် appများကို ရယူခြင်း"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"အပလီကေးရှင်းအား လက်ရှိနဲ့ လတ်တလော လုပ်ဆောင်ခဲ့သော သတင်းအချက်အလက် အသေးစိတ်အား ထုတ်ယူခွင့်ပြုရန်။ အပလီကေးရှင်းမှ သင် ဘယ် အပလီကေးရှင်းများသုံးရှိကြောင့် တွေ့ရှိနိုင်ပါသည်"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"အသုံးပြုသူများအကြား ဆက်ဆံခြင်း"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"အပလီကေးရှင်းအား စက်ပေါ်ရှိ တစ်ယောက်ထက်ပိုသော အသုံးပြုသူများအတွက် လုပ်ဆောင်ချက်များ ပြုလုပ်ခွင့်ပေးပါ။ အန္တရာယ်ရှိသော အပလီကေးရှင်းများမှ ဒီအရာကို သုံးပြီး အသုံးပြုသူများအတွင်း ကာကွယ်မှုကို ဖောက်ဖျက်နိုင်ပါသည်"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"အသုံးပြုသူများအကြား ဆက်ဆံရန် လိုင်စင် အပြည့်"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"စနစ်"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ဘလူးတုသ် အသံ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ကြိုးမဲ့ပြသခြင်း"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"မီဒီယာ အထွက်"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"စက်တစ်ခုကို ချိတ်ဆက်ရန်"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ဖန်သားပြင်ကို စက်ဆီ ပို့လွှတ်ပါ"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"စက်များကို ရှာဖွေနေပါသည် ..."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d8efcc6..f1079d1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Appen gis tillatelse til å motta og behandle Bluetooth MAP-meldinger. Dette betyr at appen kan overvåke eller slette meldinger som er sendt til enheten din, uten at du får se dem."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"hente apper som kjører"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Lar appen hente informasjon om oppgaver som kjører og som nylig har kjørt. Dette kan tillate appen å oppdage informasjon om hvilke apper som brukes på enheten."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"samhandling på tvers av brukere"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillater at appen utfører handlinger på tvers av ulike brukere på enheten. Skadelige apper kan utnytte dette til å bryte beskyttelsen mellom brukere."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full lisens til å samhandle på tvers av brukere"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skjerm"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Koble til enheten"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast skjermen til enheten"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søker etter enheter …"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index d5b152d..64d4c62 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"अनुप्रयोगलाई ब्लुटुथ MAP सन्देशहरू प्राप्त गर्न र प्रक्रिया गर्न अनुमति दिन्छ। यो अनुप्रयोगले तपाईँलाई नदेखाई आफ्नो उपकरणमा पठाइएको सन्देशहरू अनुगमन वा मेटाउन सक्दछ।"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"चलिरहेका अनुप्रयोगहरू पुनःबहाली गर्नुहोस्"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"वर्तमानमा र भरखरै चलिरहेका कार्यहरू बारेको सूचना पुनःबहाली गर्न अनुप्रयोगलाई अनुमित दिन्छ। यसले उपकरणमा प्रयोग भएका अनुप्रयोगहरूको बारेमा सूचना पत्ता लगाउन अनुप्रयोगलाई अनुमति दिन सक्छ।"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"प्रयोगकर्ताहरू तर्फ अन्तर्क्रिया गर्नुहोस्"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"अनुप्रयोगलाई उपकरणमा विभिन्न प्रयोगकर्ताहरू मार्फत कार्यहरू गर्न अनुमति दिन्छ। खराब अनुप्रयोगहरूले यो प्रयोगकर्ताहरू बिच सुरक्षा बिथोल्न प्रयोग गर्न सक्ने छन्।"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"कुराकानी प्रयोगकर्ताहरू बिच अन्तर्क्रिया गर्न पूर्ण अनुमति"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"तपाईँको फोनमा भण्डारण भएको ब्राउजरको इतिहास वा बुकमार्कहरू परिवर्तन गर्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। यसले सायद ब्राउजर डेटालाई मेट्न वा परिवर्तन गर्नको लागि अनुप्रयोगलाई अनुमति दिन्छ। नोट: वेब ब्राउज गर्ने क्षमतासहितका अन्य अनुप्रयोगहरू वा तेस्रो- पक्ष ब्राउजरद्वारा सायद यस अनुमतिलाई लागु गर्न सकिंदैन।"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"एउटा आलर्म सेट गर्नुहोस्"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"स्थापना गरिएको सङ्केत घडी अनुप्रयोगमा सङ्केत समय मिलाउन अनुप्रयोगलाई अनुमति दिन्छ। केही सङ्केत घडी अनुप्रयोगहरूले यो सुविधा कार्यान्वयन नगर्न सक्छन्।"</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"भ्वाइसमेलहरू लेख्नुहोस्"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश परिमार्जन गर्न र हटाउन अनुप्रयोगलाई अनुमति दिनुहोस्।"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"भ्वाइसमेल थप गर्नुहोस्"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश थप्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"प्यकेजहरूको निरीक्षण गर्नुहोस्"</string>
@@ -1399,7 +1399,7 @@
     <string name="permlab_recovery" msgid="3157024487744125846">"अद्यावधिक र रिकभरी प्रणालीको साथ अन्तर्क्रिया"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"अनुप्रयोगलाई रिकभरी प्रणाली र प्रणाली अद्यावधिकहरूको साथ अन्तर्क्रिया गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_createMediaProjection" msgid="4941338725487978112">"मिडिया प्रक्षेपण सत्रहरू सिर्जना गर्नुहोस्"</string>
-    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"मिडिया प्रक्षेपण सत्र सिर्जना गर्न अनुप्रयोग लाई अनुमति दिन्छ। यी सत्रले प्रदर्शन र अडियो सामग्री खिच्ने क्षमताका अनुप्रयोगहरू प्रदान गर्न सक्छन्। सामान्य अनुप्रयोगहरूको कहिल्यै पनि आवश्यक पर्दैन।"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"मिडिया प्रक्षेपण सत्र सिर्जना गर्न अनुप्रयोगलाई अनुमति दिन्छ। यी सत्रले प्रदर्शन र अडियो सामग्री खिच्ने क्षमताका अनुप्रयोगहरू प्रदान गर्न सक्छन्। सामान्य अनुप्रयोगहरूको कहिल्यै पनि आवश्यक पर्दैन।"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"जुम नियन्त्रणको लागि दुई चोटि टच गर्नुहोस्"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"विजेट थप गर्न सकिँदैन।"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"जानुहोस्"</string>
@@ -1528,7 +1528,7 @@
     <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G डेटा बन्द छ"</string>
     <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"सेलुलर डेटा बन्द छ"</string>
     <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"वाइफाइ डेटा बन्द छ"</string>
-    <string name="data_usage_limit_body" msgid="6131350187562939365">"सिमा पुग्यो"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"सीमा पुग्यो"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G डेटा सीमा भन्दा पार भएको छ"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G डेटा SIMा नाघ्यो"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"सेलुलर डेटा सीमा नाघ्यो"</string>
@@ -1567,7 +1567,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"प्रणाली"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ब्लुटुथ अडियो"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ताररहित प्रदर्शन"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"मिडियाको उत्पादन"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"उपकरणमा जडान गर्नुहोस्"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"उपकरणलाई स्क्रिनमा कास्ट गर्नुहोस्"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"उपकरणको खोजी गरिँदै..."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7bcbbe2..8270df9 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Hiermee kan de app Bluetooth MAP-berichten ontvangen en verwerken. Dit betekent dat de app berichten die naar uw apparaat zijn verzonden, kan controleren of verwijderen zonder ze aan u te laten zien."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"actieve apps ophalen"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Hiermee kan de app informatie ophalen over actieve en recent uitgevoerde taken. Zo kan de app informatie vinden over welke apps op het apparaat worden gebruikt."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interactie tussen gebruikers"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Hiermee kan de app acties uitvoeren voor verschillende gebruikers van het apparaat. Schadelijke apps kunnen dit gebruiken om de beveiliging tussen gebruikers te schenden."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volledige toestemming voor interactie tussen gebruikers"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systeem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadloze weergave"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Verbinding maken met apparaat"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Scherm casten naar apparaat"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Zoeken naar apparaten…"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 3822c4e..4bc6541 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Pozwala aplikacji na odbieranie i przetwarzanie komunikatów Bluetooth MAP. Oznacza to, że może ona bez Twojej wiedzy monitorować i usuwać komunikaty przesyłane do Twojego urządzenia."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"pobieranie uruchomionych aplikacji"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Pozwala aplikacji na pobieranie informacji o aktualnie i niedawno działających zadaniach. Dzięki temu aplikacja może uzyskać informacje o tym, które aplikacje są używane na urządzeniu."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcje między użytkownikami"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umożliwia aplikacji wykonywanie działań dotyczących różnych użytkowników urządzenia. Złośliwe aplikacje mogą to wykorzystać do złamania zabezpieczeń na kontach użytkowników."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"pełna licencja na interakcje między użytkownikami"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wyświetlacz bezprzewodowy"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Połącz z urządzeniem"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prezentuj ekran na urządzeniu"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Szukam urządzeń…"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5941e18..e782435 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite à aplicação receber e processar mensagens MAP Bluetooth, o que significa que a aplicação poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem lhas mostrar."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"obter aplicações em execução"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que a aplicação recupere informações acerca de tarefas executadas atual e recentemente. Isto pode permitir que a aplicação descubra informações acerca de quais as aplicações utilizadas no dispositivo."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre utilizadores"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que a aplicação execute ações com diferentes utilizadores no dispositivo. Aplicações maliciosas poderão utilizar esta opção para violar a proteção entre utilizadores."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licença completa para interagir entre utilizadores"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualização sem fios"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Ligar ao dispositivo"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir ecrã para o dispositivo"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"A pesquisar dispositivos…"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index abc0b5e..114485b 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite que o aplicativo receba e processe mensagens Bluetooth MAP. Isso significa que o aplicativo pode monitorar ou excluir as mensagens enviadas para o dispositivo sem mostrá-las para você."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicativos em execução"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite que o aplicativo obtenha informações sobre tarefas em execução atuais e recentes. Pode permitir que o aplicativo descubra informações sobre os aplicativos usados ​​no dispositivo."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagir entre os usuários"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que o aplicativo execute ações entre os diversos usuários do aparelho. Aplicativos mal-intencionados podem usar isto para violar a proteção entre os usuários."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"permissão total para interagir entre os usuários"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite que o aplicativo modifique o histórico ou os favoritos do navegador armazenados no telefone. Pode permitir que o aplicativo apague ou modifique os dados do navegador. Observação: pode não ser aplicável a navegadores de terceiros e outros aplicativos com capacidade de navegação na web."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"definir um alarme"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite que o aplicativo defina um alarme em um aplicativo despertador instalado. Alguns aplicativos despertador podem não implementar este recurso."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"gravar correio de voz"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Permite que o app modifique e remova mensagens da caixa de entrada do correio de voz."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"adicionar correio de voz"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite que o aplicativo adicione mensagens a sua caixa de entrada do correio de voz."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"ler correio de voz"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Permite que o app leia seus correios de voz."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modifique as permissões de geolocalização de seu navegador"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite que o aplicativo modifique as permissões de geolocalização do navegador. Aplicativos maliciosos podem usar isso para permitir o envio de informações locais para sites arbitrários."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"verificar pacotes"</string>
@@ -1390,10 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que o aplicativo se associe a um serviço de agente de confiança."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de atualizações e recuperação"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permite que um aplicativo interaja com o sistema de recuperação e as atualizações do sistema."</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Criar sessões de projeção de mídia"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Permite que um aplicativo crie sessões de projeção de mídia. As sessões podem fornecer aos aplicativos a capacidade de capturar conteúdo de tela e de áudio. Isso nunca deve ser necessário em aplicativos normais."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Não foi possível adicionar widget."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
@@ -1518,20 +1516,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Toque p/ ver uso e config."</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Os dados 2G-3G foram desativados"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Os dados 4G foram desativados"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Dados da rede cel. desativados"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Os dados Wi-Fi foram desativados"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"Limite atingido"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Limite de dados 2G-3G excedido"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Limite de dados 4G excedido"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Lim. de dados rede cel. excedido"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Limite de dados Wi-Fi excedido"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> acima do limite especificado."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Dados de segundo plano restritos"</string>
@@ -1567,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Display sem fio"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar ao dispositivo"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir tela para dispositivo"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Procurando dispositivos…"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f1a4b96..84413bb 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Permite aplicației să primească și să proceseze mesaje MAP prin Bluetooth. Aceasta înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitiv fără a le afișa."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"preluare aplicaţii care rulează"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicaţiei să preia informaţiile despre activităţile care rulează în prezent şi care au rulat recent. În acest fel, aplicaţia poate descoperi informaţii despre aplicaţiile care sunt utilizate pe dispozitiv."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interacţiune între utilizatori"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite aplicaţiei să efectueze acţiuni pentru diferiţi utilizatori pe dispozitiv. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a încălca protecţia între utilizatori."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenţă completă pentru interacţiune între utilizatori"</string>
@@ -719,8 +723,8 @@
     <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_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">"conectare la un serviciu de trasee multimedia"</string>
-    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de trasee multimedia. 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>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite deținătorului să se conecteze la interfața de nivel superior a unui serviciu de trasee multimedia. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"se conectează la un serviciu de vis"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite deținătorului să se conecteze la interfața superioară a unui serviciu de vis. Această opțiune nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"apelarea aplicației de configurare furnizată de operator"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicaţiei să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicaţia poate şterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicaţii cu capacităţi de navigare pe web."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicaţiei să seteze o alarmă într-o aplicaţie de ceas cu alarmă instalată. Este posibil ca unele aplicaţii de ceas cu alarmă să nu implementeze această funcţie."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"scrierea mesajelor vocale"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Permite aplicației să modifice și să elimine mesaje din secțiunea de mesaje vocale primite."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite aplicaţiei să adauge mesaje în Mesaje primite în mesageria vocală."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"citirea mesajelor vocale"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Permite aplicației să citească mesajele vocale."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modificare permisiuni pentru locaţia geografică a browserului"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicaţiei să modifice permisiunile privind locaţia geografică a browserului. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a permite trimiterea informaţiilor privind locaţia către site-uri web arbitrare."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"verificare pachete"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Ecran wireless"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectați-vă la dispozitiv"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Proiectați ecranul pe dispozitiv"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Se caută dispozitive..."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d74a215..99a7c13 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Получение и обработка сообщений Bluetooth MAP. Отслеживание и удаление непрочитанных сообщений."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"Получение данных о запущенных приложениях"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Приложение сможет получать информацию о недавно запущенных и выполняемых задачах, а следовательно, и о приложениях, используемых на устройстве."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Взаимодействие с аккаунтами всех пользователей"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Приложение сможет выполнять действия во всех аккаунтах на этом устройстве. При этом защита от вредоносных приложений может быть недостаточной."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Полное взаимодействие с аккаунтами всех пользователей"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Приложение сможет изменять историю или закладки браузера, сохраненные на телефоне, а также удалять и изменять данные браузера. Обратите внимание: браузеры независимых поставщиков или другие приложения для просмотра веб-страниц могут не применять это разрешение."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"Установка будильника"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Приложение сможет настраивать будильник. Функция поддерживается не во всех программах."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"запись голосовых сообщений"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Изменение и удаление сообщений из голосовой почты."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"Добавление голосовых сообщений"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Приложение сможет добавлять голосовые сообщения в папку \"Входящие\"."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"Проверка пакетов"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Беспроводной монитор"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Подключение к устройству"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Подключение к удаленному дисплею"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Поиск устройств…"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 38b153d..b8622a5 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"බ්ලූටූත් MAP පණිවිඩ සොයා ලබාගැනීමට සහ ක්‍රියාත්මක කිරීමට යෙදුමට අවසර දෙන්න. යෙදුම නිරීක්ෂණය කරනු ලබන අතර ඔබට ලැබුන පණිවිඩ පෙන්වීමෙන් තොරවම මකා දැමිය හැකි බව මෙමඟින් අදහස් කරයි."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"ධාවනය වන යෙදුම් ලබාගැනීම"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"දැනට සහ මෑත ක්‍රියාත්මක කාර්යයන් පිළිබඳ විස්තරාත්මක තොරතුරු සොයා ලබාගැනීමට යෙදුමට ඉඩ දෙන්න. මෙය කුමන යෙදුම් උපාංගයේ භාවිතා කරන්නේද යන තොරතුරු යෙදුම්වලට සොයා ගැනීමට ඉඩ දිය හැක."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"පරිශීලකයන් අතර අන්තර්ක්‍රියාකාරී වන්න"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"උපාංගයේ විවිධ පරිශීලකයන් හරහා ක්‍රියාවන් දැක්වීමට යෙදුමට අවසර දෙන්න. පරිශීලකයන් අතර ආරක්ෂාව කඩකිරීමට අනිෂ්ට යෙදුම් විසින් මෙය භාවිතා කිරීමට ඉඩ ඇත."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"පරිශීලකයන් අතර අන්තර් ක්‍රියාකාරී වීමට සම්පූර්ණ බලපත්‍රය"</string>
@@ -1008,16 +1012,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ඔබගේ දුරකථනයේ ආචයනය කරන ලද බ්‍රව්සර ඉතිහාසය හෝ පිටුසන වෙනස් කිරීමට යෙදුමට අවසර දෙන්න. ඔබගේ බ්‍රව්සර දත්ත මැකීමට හෝ වෙනස් කිරීමට අනිෂ්ට යෙදුම් මෙය භාවිත කරයි. සටහන: වෙබ් බ්‍රව්සර අවශ්‍යතාවය සමග තෙවෙනි පාර්ශව බ්‍රව්සර හෝ වෙනත් යෙදුම් විසින් මෙම අවසරය බල ගැන්විය හැක."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"සීනුවක් සැකසීම"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"ස්ථාපනය කරන ලද සීනු ඔරලෝසු යෙදුමේ සීනුව සකස් කරන්නට යෙදුමට ඉඩ දෙන්න. ඇතැම් සීනු ඔරලෝසු යෙදුම් මෙම අංගය ක්‍රියාවට නංවා නොතිබීමට ඉඩ තිබේ."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"හඬ තැපෑල් ලියන්න"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ඔබගේ හඬ තැපෑලේ එන ලිපි වෙත එන පණිවිඩ ඉවත් කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"හඬ තැපෑල එක් කිරීම"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ඔබගේ හඬ තැපෑලේ එන ලිපි වෙත එන පණිවිඩ එකතු කිරීමට යෙදුමට අවසර දෙන්න."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"පැකේජ සත්‍යාපනය කරන්න"</string>
@@ -1393,10 +1393,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"යෙදුමකට විශ්වාසනීය ඒජන්ත සේවාවකට බැඳීමට අවසර දේ."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"ප්‍රතිසාධන පද්ධතිය සහ යාවත්කාලීන සමඟ කටයුතු කරන්න"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"යෙදුමකට ප්‍රතිසාධන පද්ධතිය සහ පද්ධති යාවත්කාලීන සමඟ කටයුතු කිරීමට ඉඩ දෙන්න."</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"මාධ්‍ය ප්‍රක්ෂේපන සැසියන් සාදන්න"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"මාධ්‍ය ප්‍රක්ෂේපන සැසියන් සාදන්න යෙදුමට ඉඩ දෙන්න. ශ්‍රව්‍ය අන්තර්ගතයන් සහ දර්ශන ලබා ගැනීමට හැකියාව යෙදුම් වලට මෙම සැසියන් ලබාගත හැක. සමාන්‍ය යෙදුම් සඳහා කවදාවත් අවශ්‍ය නොවේ."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"විශාලන පාලනය සඳහා දෙවරක් ස්පර්ශ කරන්න"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"විජටය එකතු කිරීමට නොහැකි විය."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"යන්න"</string>
@@ -1521,20 +1519,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"දත්ත භාවිතා අවවාදය"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"භාවිතය සහ සැකසීම් බැලීමට ස්පර්ශ කරන්න."</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G දත්ත නැත"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G දත්ත නැත"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"සෙලියුලර් දත්ත අක්‍රියයි"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi දත්ත අක්‍රියයි"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"සීමාව ළඟාවී ඇත"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G දත්ත සීමාව ඉක්මවන ලදි"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G දත්ත සීමාව ඉක්මවා යන ලදි"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"සෙලියුලර් දත්ත සීමාව ඉක්මවා තිබේ"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi දත්ත සීමාව ඉක්මවා යන ලදි"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"සඳහන් කළ සීමාවට වඩා <xliff:g id="SIZE">%s</xliff:g> වැඩිය."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"පසුබිම් දත්ත සිමා කරන ලදි"</string>
@@ -1570,7 +1562,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"පද්ධතිය"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"බ්ලූටූත් ශ්‍රව්‍ය"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"රැහැන් රහිත දර්ශනය"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"මාධ්‍ය ප්‍රතිදානය"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"උපාංගයට සම්බන්ධ වන්න"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"තිරය උපාංගයට යොමු කරන්න"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"උපාංග සඳහා සොයමින්…"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 63bb72b..fdfcd82 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Umožňuje aplikácii prijímať a spracovávať správy MAP rozhrania Bluetooth. Znamená to, že aplikácia môže sledovať správy odoslané na vaše zariadenie alebo ich odstrániť bez toho, aby sa vám zobrazili."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"načítať spustené aplikácie"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Umožňuje aplikácii načítať informácie o aktuálne či nedávno spustených úlohách. Toto povolenie môže aplikácii umožniť objaviť informácie o tom, ktoré aplikácie sa na zariadení používajú."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcie naprieč používateľmi"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umožňuje aplikácii vykonávať akcie naprieč rôznymi používateľmi zariadenia. Škodlivé aplikácie môžu toto povolenie zneužiť na obídenie ochrany medzi používateľmi."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"plná licencia na interakcie naprieč používateľmi"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Umožňuje aplikácii upraviť históriu prehliadača alebo záložky uložené v telefóne. Aplikácia s týmto povolením môže vymazať alebo upraviť údaje prehliadača. Poznámka: Toto povolenie nemôžu vynucovať prehliadače tretích strán ani žiadne ďalšie aplikácie umožňujúce prehliadanie webu."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"nastaviť budík"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Umožňuje aplikácii nastaviť budík v nainštalovanej aplikácii budík. Niektoré aplikácie budíka nemusia túto funkciu implementovať."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"zapisovanie do hlasovej schránky"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Povoľuje aplikácii upravovať a odstraňovať správy z hlasovej schránky."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"pridať hlasovú schránku"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Umožní aplikácii pridávať správy do doručenej pošty hlasovej schránky."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"čítanie hlasových správ"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Umožňuje aplikácii čítať vaše hlasové správy."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"zmeniť povolenia prehliadača poskytovať informácie o zemepisnej polohe"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Umožňuje aplikácii zmeniť povolenia prehliadača na poskytovanie údajov o zemepisnej polohe. Škodlivé aplikácie to môžu použiť na odosielanie informácií o polohe ľubovoľným webovým stránkam."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"overiť balíky"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrôtový displej"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Pripojenie k zariadeniu"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prenos obraz. do zariad."</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Prebieha vyhľadávanie zariadení…"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index cda7606..2cd858e 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Aplikaciji omogoča prejemanje in obdelavo sporočil Bluetooth MAP. To pomeni, da lahko aplikacija nadzira in izbriše sporočila, poslana v napravo, ne da bi vam jih prikazala."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"dobivanje programov, ki se izvajajo"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Aplikaciji omogoča prejemanje podatkov o trenutnih in nedavno izvajajočih se opravilih. S tem lahko aplikacija odkrije podatke o aplikacijah, ki se uporabljajo v napravi."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interakcija z uporabniki"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Aplikaciji omogoča izvajanje dejanj za različne uporabnike v napravi. Zlonamerne aplikacije lahko to uporabijo za kršitev zaščite med uporabniki."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"polna licenca za interakcijo z uporabniki"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Aplikaciji omogoča spreminjanje zgodovine ali zaznamkov brskalnika v telefonu. S tem lahko aplikacija izbriše ali spremeni podatke v brskalniku. Opomba: Tega dovoljenja ne morejo uveljavljati drugi brskalniki ali aplikacije, s katerimi je mogoče brskati po spletu."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"nastavitev alarma"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Programu omogoča nastavitev alarma v nameščenem programu budilke. Nekateri programi budilke morda nimajo te funkcije."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"snemanje sporočil v odzivniku"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Aplikaciji omogoča spreminjanje in odstranjevanje sporočil iz odzivnika."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"dodajanje odzivnika"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Programu omogoča dodajanje sporočil prejetim sporočilom odzivnika."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"branje sporočil v odzivniku"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Aplikaciji omogoča branje sporočil v odzivniku."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Spreminjanje dovoljenj za geolokacijo brskalnika"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Programu omogoča spreminjanje geolokacijskih dovoljenj v brskalniku. Zlonamerni programi lahko to izkoristijo za pošiljanje podatkov o lokaciji poljubnim spletnim mestom."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"preveri pakete"</string>
@@ -1516,10 +1516,10 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Opozorilo o uporabi podatkov"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Dotaknite se za uporabo in nast."</string>
-    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Prenos pod. v omr. 2G/3G je izk."</string>
-    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Prenos pod. v omrež. 4G je izkl."</string>
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"Podatki v omrežju 2G/3G so izkl."</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Podatki v omrežju 4G so izklop."</string>
     <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Prenos mob. podatkov izklopljen"</string>
-    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Prenos pod. v om. Wi-Fi je izkl."</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Prenos pod. prek Wi-Fi je izkl."</string>
     <string name="data_usage_limit_body" msgid="6131350187562939365">"Omejitev je dosežena"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Omejit. za podat. 2G-3G presež."</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Omejitev za podat. 4G presež."</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Brezžični prikaz"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Izhod predstavnosti"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezovanje z napravo"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Predvajanje zaslona v napravi"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Iskanje naprav …"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c234818..25bf1a9 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Дозвољава апликацији да прима и обрађује Bluetooth MAP поруке. То значи да апликација може да надгледа или брише поруке које се шаљу на уређај, а да вам их не прикаже."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"преузимање покренутих апликација"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Дозвољава апликацији да преузима информације о актуелним и недавно покренутим задацима. Ово може да омогући апликацији да открије информације о томе које се апликације користе на уређају."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"интеракција између корисника"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Дозвољава апликацији да обавља радње између различитих корисника на уређају. Злонамерне апликације могу да користе ово да би угрозиле заштиту између корисника."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"пуна лиценца за интеракцију између корисника"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Бежични екран"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Повежите са уређајем"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Пребаците екран на уређај"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Тражење уређаја…"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 913bc90..7eee11b 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Tillåter att appen tar emot och hanterar Bluetooth MAP-meddelanden. Detta innebär att appen kan övervaka eller ta bort meddelanden som skickats till enheten utan att visa dem för dig."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"hämta appar som körs"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Tillåter att appen hämtar information om nyligen körda och pågående aktiviteter. Detta kan innebära att appen tillåts ta reda på vilka appar som används på enheten."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"interagera mellan användare"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillåter att appen utför åtgärder mellan användare på enheten. Skadliga appar kan använda detta som ett sätt att kringgå skyddet mellan användare."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fullständig behörighet att interagera mellan användare"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådlös skärm"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieuppspelning"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Anslut till enhet"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Överför skärmen till enheten"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Söker efter enheter ..."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index acbef24..a00ea16 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Inaruhusu programu kupokea na kuchakata ujumbe wa Bluetooth MAP. Hii inamaanisha programu inaweza kufuatilia au kufuta ujumbe unaotumwa kwenye kifaa chako pasipo kukuonyesha ujumbe huo."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"rudisha programu zinazoendeshwa"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Inaruhusu programu kurudisha taarifa kuhusu kazi zinazoendeshwa sasa na hivi karibuni. Hii inaweza kuruhusu programu kugundua taarifa kuhusu ni programu zipi zinazotumika kwenye kifaa."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kuwasiliana na watumiaji wengine"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Inaruhusu programu kutenda vitendo kwa watumiaji tofauti kwenye kifaa. Programu hasidi huenda zikatumia hii ili kukiuka ulinzi kati ya watumiaji."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"leseni kamili ili kushirikiana na watumiaji"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Inaruhusu programu kurekebisha historia ya Kivinjari au alamisho zilizohifadhiwa kwenye simu yako. Hii huenda ikaruhusu programu kufuta au kurekebisha data ya Kivinjari. Kumbuka: huenda idhini hii isitekelezwe na vivinjari vingine au programu nyingine zenye uwezo wa kuvinjari wavuti."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"weka kengele"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Inaruhusu programu kuweka kengele katika programu iliyosakinishwa ya kengele. Programu zingine za kengele zinawezakosa kutekeleza kipengee hiki."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"andika ujumbe wa sauti"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Huruhusu programu kubadili na kuondoa ujumbe kwenye kikasha chako cha ujumbe wa sauti."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ongeza barua ya sauti"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Huruhusu programu kuongeza mawasiliano kwenye kikasha cha ujumbe wa sauti."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"soma ujumbe wa sauti"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Huruhusu programu isome ujumbe wako wa sauti."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Rekebisha vibali vya Kivinjari cha eneo la jio"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Inaruhusu programu kurekebisha ruhusa za eneo la jio za kivinjari. Programu hasidi zinaweza tumia hii kuruhusu kutuma taarifa ya eneo kwa wavuti holela."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"thibitisha furushi"</string>
@@ -1523,7 +1523,7 @@
     <string name="data_usage_limit_body" msgid="6131350187562939365">"Kikomo kimefikiwa"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Kikomo cha data ya 2G-3G kimezidishwa"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Kikomo cha data cha 4G kimezidishwa"</string>
-    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Kikomo cha data ya simu za mkononi kimevukwa"</string>
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Umezidi kikomo cha data ya simu"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Taarifa za Wi-fi zimevuka kiwanga"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> juu ya kikomo kilichobainishwa."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Data ya mandhari nyuma imezuiwa"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Uonyeshaji usiotumia waya"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Unganisha kwenye kifaa"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Tuma skrini kwenye kifaa"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Inatafuta vifaa..."</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index eacc824..7d4478e 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"புளூடூத் MAP செய்திகளைப் பெற மற்றும் செயல்படுத்த பயன்பாட்டை அனுமதிக்கிறது. அதாவது பயன்பாட்டால் சாதனத்திற்கு அனுப்பப்பட்ட செய்திகளை, உங்களிடம் காட்டாமலே கண்காணிக்கவோ, நீக்கவோ முடியும்."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"இயங்கும் பயன்பாடுகளை மீட்டெடுத்தல்"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"நடப்பில் மற்றும் சமீபத்தில் இயங்கும் காரியங்களின் தகவலைப் பெற பயன்பாட்டை அனுமதிக்கிறது. சாதனத்தில் எந்தப் பயன்பாடுகள் பயன்படுத்தப்படுகின்றன என்பது குறித்த தகவலைக் கண்டறிய பயன்பாட்டை இது அனுமதிக்கலாம்."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"பிற பயனர்களுடன் தொடர்புகொள்ளுதல்"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"சாதனத்தில் உள்ள பல்வேறு பயனர்கள் அனைவரிலும் செயல்களைச் செய்ய பயன்பாட்டை அனுமதிக்கிறது. பயனர்கள் இடையேயான பாதுகாப்பை மீற தீங்கிழைக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"பிற பயனர்களுடன் தொடர்புகொள்வதற்கான முழு உரிமம்"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"அமைப்பு"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"புளூடூத் ஆடியோ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"வயர்லெஸ் காட்சி"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"மீடியா வெளியீடு"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"சாதனத்துடன் இணைக்கவும்"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"திரையிலிருந்து சாதனத்திற்கு அனுப்புக"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"சாதனங்களைத் தேடுகிறது..."</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index b373cc7..1868818 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"బ్లూటూత్ MAP సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. అనువర్తనం మీ పరికరానికి పంపబడిన సందేశాలను పర్యవేక్షించగలదని లేదా మీకు చూపకుండానే తొలగించగలదని దీనర్థం."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"అమలవుతున్న అనువర్తనాలను పునరుద్ధరించడం"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ప్రస్తుతం మరియు ఇటీవల అమలవుతున్న విధుల గురించి వివరణాత్మక సమాచారాన్ని తిరిగి పొందడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది పరికరంలో ఉపయోగించబడిన అనువర్తనాల గురించి సమాచారాన్ని కనుగొనడానికి అనువర్తనాన్ని అనుమతించవచ్చు."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"వినియోగదారుల మధ్య పరస్పర చర్య చేయడం"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"పరికరంలోని విభిన్న వినియోగదారుల తరపున చర్యలను అమలు చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన అనువర్తనాలు వినియోగదారుల మధ్య రక్షణను ఉల్లంఘించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"వినియోగదారుల మధ్య పరస్పర చర్య చేయడానికి పూర్తి లైసెన్స్"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"సిస్టమ్"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"బ్లూటూత్ ఆడియో"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"వైర్‌లెస్ డిస్‌ప్లే"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"మీడియా అవుట్‌పుట్"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"పరికరానికి కనెక్ట్ చేయండి"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"స్క్రీన్‌ను పరికరానికి ప్రసారం చేయండి"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"పరికరాల కోసం శోధిస్తోంది…"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 31ad764..a5d7a36 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -162,7 +162,7 @@
     <string name="silent_mode_silent" msgid="319298163018473078">"ปิดเสียง"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"เสียงเรียกเข้าแบบสั่น"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"เปิดเสียง"</string>
-    <string name="shutdown_progress" msgid="2281079257329981203">"กำลังปิดระบบ..."</string>
+    <string name="shutdown_progress" msgid="2281079257329981203">"กำลังปิด..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"แท็บเล็ตของคุณจะปิดการทำงาน"</string>
     <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"นาฬิกาจะปิดการทำงาน"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"โทรศัพท์ของคุณจะปิดเครื่อง"</string>
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"อนุญาตให้แอปรับและประมวลผลข้อความ MAP สำหรับบลูทูธ ซึ่งหมายความว่าแอปจะสามารถตรวจสอบหรือลบข้อความที่ส่งไปยังอุปกรณ์ของคุณได้โดยไม่ต้องแสดงให้คุณเห็น"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"เรียกแอปพลิเคชันที่ทำงานอยู่"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"อนุญาตให้แอปพลิเคชันเรียกดูข้อมูลเกี่ยวกับงานที่ดำเนินการอยู่ในขณะนี้และเมื่อเร็วๆ นี้ ซึ่งอาจทำให้แอปพลิเคชันสามารถค้นข้อมูลได้ว่าอุปกรณ์นี้ใช้แอปพลิเคชันใดบ้าง"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"โต้ตอบระหว่างผู้ใช้"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"อนุญาตให้แอปพลิเคชันทำงานได้กับผู้ใช้หลายรายบนอุปกรณ์นี้ แอปพลิเคชันที่เป็นอันตรายอาจใช้การทำงานนี้ในการบุกรุกการป้องกันระหว่างผู้ใช้"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ใบอนุญาตฉบับเต็มสำหรับการโต้ตอบระหว่างผู้ใช้"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ระบบ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"การแสดงผลแบบไร้สาย"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"เชื่อมต่อกับอุปกรณ์"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ส่งหน้าจอไปยังอุปกรณ์"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"กำลังค้นหาอุปกรณ์…"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 36990ee..bb74ca3 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Pinapayagan ang app na makatanggap at makapagproseso ng mga mensahe ng Bluetooth MAP. Nangangahulugan ito na maaaring subaybayan o i-delete ng app ang mga mensaheng ipinapadala sa iyong device nang hindi ipinapakita ang mga ito sa iyo."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"bawiin ang tumatakbong apps"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Pinapayagan ang app na kumuha ng impormasyon tungkol sa mga kasalukuyan at kamakailang gumaganang gawain. Maaari nitong payagan ang app na tumuklas ng impormasyon tungkol sa kung aling mga application ang ginagamit sa device."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"makipag-ugnayan sa kabuuan ng mga user"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Binibigyang-daan ang app upang magsagawa ng mga pagkilos sa kabuuan ng iba\'t ibang mga user sa device. Maaari itong gamitin ng nakakahamak na apps upang lumabag sa proteksyon sa pagitan ng mga user."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ganap na lisensya upang makipag-ugnayan sa kabuuan ng mga user"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Kumonekta sa device"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"I-cast ang screen sa device"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Naghahanap ng mga device…"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 3f79c61..927e7cb 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Uygulamanın Bluetooth MAP iletilerini alıp işlemesine izin verir. Bu izin, uygulamanın cihazınıza gönderilen iletileri izleyebileceği veya size göstermeden silebileceği anlamına gelir."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"çalışan uygulamaları al"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Uygulamaya o anda ve son çalışan görevler hakkında bilgi alma izni verir. Bu izin, uygulamanın cihaz tarafından kullanılan uygulamalar hakkında bilgi elde etmesine olanak sağlayabilir."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kullanıcılar arasında etkileşim kurma"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Uygulamaya cihazdaki farklı kullanıcılar arasında işlem gerçekleştirme izni verir. Kötü amaçlı uygulamalar bu izinle kullanıcılar arasındaki korumayı ihlal edebilir."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"kullanıcılar arasında etkileşim kurmak için tam izin"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Uygulamaya Tarayıcı geçmişini ve telefonunuzda depolanan yer işaretlerini değiştirme izni verir. Bu izin, uygulamanın Tarayıcı geçmişini silmesine ve değiştirmesine olanak sağlar. Not: Bu izin, üçüncü taraf cihazlar veya Web\'e göz atma işlevine sahip diğer uygulamalar tarafından kullanılmayabilir."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"alarm ayarla"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Uygulamaya, çalar saat uygulamasının alarmını ayarlama izni verir. Bazı çalar saat uygulamaları bu özelliği uygulayamayabilir."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"sesli mesaj yaz"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Uygulamanın sesli mesaj gelen kutunuzdaki mesajları değiştirmesine ve kaldırmasına izin verir."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"sesli mesaj ekle"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Uygulamaya, sesli mesaj gelen kutunuza mesaj ekleme izni verir."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"sesli mesaj oku"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Uygulamanın sesli mesajlarınızı okumasına izin verir."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Tarayıcı\'nın coğrafi konum izinlerini değiştir"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Uygulamaya, Tarayıcı\'nın coğrafi konum izinlerini değiştirme izni verir. Kötü amaçlı uygulamalar keyfi web sitelerine konum bilgisi gönderilmesini sağlamak için bunu kullanabilirler."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"paketleri doğrula"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Kablosuz ekran"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Cihaza bağlanın"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekranı cihaza yayınlayın"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Cihaz aranıyor…"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index ac415eb..3a217be 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Дозволяє додаткові отримувати й обробляти повідомлення Bluetooth MAP. Це означає, що додаток може відстежувати чи видаляти повідомлення, надіслані на ваш пристрій, навіть не показуючи їх вам."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"отримувати запущені програми"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Дозволяє програмі отримувати інформацію про поточні й останні запущені завдання. Це може дозволити програмі виявляти інформацію про програми, які використовуються на пристрої."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"взаємодіяти між користувачами"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Дозволяє програмі виконувати дії щодо різних користувачів на пристрої. Шкідливі програми можуть використовувати це для порушення захисту окремих користувачів."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"повна ліцензія на взаємодію між користувачами"</string>
@@ -1386,8 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозволяє додатку прив’язуватися до служби довірчих агентів."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Взаємодіяти з оновленнями системи та системою відновлення."</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Дозволяє додатку взаємодіяти із системою відновлення й оновленнями системи."</string>
-    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Створювати сеанси проектування медіа"</string>
-    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Додаток може створювати сеанси проектування медіа. Під час цих сеансів додатки зможуть збирати аудіовміст і вміст дисплея. Не використовується звичайними додатками."</string>
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Створювати сеанси трансляції вмісту"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Додаток може створювати сеанси трансляції вмісту. Під час цих сеансів додаток зможе отримати доступ до аудіо й зображення на екрані. Не використовується звичайними додатками."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двічі торкніться, щоб керувати масштабом"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Не вдалося додати віджет."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Йти"</string>
@@ -1516,7 +1520,7 @@
     <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"Дані 4G вимкнено"</string>
     <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Мобільні дані вимкнено"</string>
     <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Дані Wi-Fi вимкнено"</string>
-    <string name="data_usage_limit_body" msgid="6131350187562939365">"Досягнуто ліміту"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"Перевищено ліміт"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Перевищено ліміт даних 2G–3G"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Перевищено ліміт даних 4G"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Перевищено ліміт мобільних даних"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудіо Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Бездротовий екран"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Вивід медіа-даних"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Під’єднатися до пристрою"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Транслювати екран на пристрій"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Пошук пристроїв…"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index c3feb4c..216a726 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"‏ایپ کو بلوتوٹھ MAP پیغامات وصول اور ان پر کارروائی کرنے کی اجازت دیتی ہے۔ اس کا مطلب یہ ہے کہ ایپ آپ کے آلہ پر ارسال کردہ پیغامات آپ کو دکھائے بغیر ان پر نگاہ رکھ یا انہیں حذف کرسکتی ہے۔"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"چل رہی ایپس کی بازیافت کریں"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ایپ کو موجودہ اور حالیہ چل رہے ٹاسکس کے بارے میں معلومات بازیافت کرنے کی اجازت دیتا ہے۔ یہ ایپ کو اس بارے میں معلومات دریافت کرنے کی اجازت دے سکتا ہے کہ آلہ پر کون سی ایپلیکیشنز استعمال کی جاتی ہیں۔"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"سبھی صارفین کے ساتھ تعامل کریں"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"ایپ کو آلے پر موجود مختلف صارفین کے بیچ کارروائیاں انجام دینے کی اجازت دیتا ہے۔ نقصان دہ ایپس صارفین کے مابین تحفظ کی خلاف ورزی کرنے کیلئے اسے استعمال کرسکتی ہیں۔"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"سبھی صارفین کے ساتھ تعامل کرنے کیلئے مکمل لائسنس"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ایپ کو آپ کے فون پر اسٹور کردہ براؤزر کی سرگزشت یا بک مارکس میں ترمیم کرنے کی اجازت دیتا ہے۔ یہ ایپ کو براؤزر کا ڈیٹا مٹانے یا اس میں ترمیم کرنے کی اجازت دے سکتا ہے۔ نوٹ: یہ اجازت تیسرے فریق کے براؤزرز یا ویب براؤزنگ کی لیاقتوں والی دیگر ایپلیکیشنز کے ذریعہ نافذ نہیں کی جاسکتی ہے۔"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"ایک الارم سیٹ کریں"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"ایپ کو ایک انسٹال کردہ الارم گھڑی کی ایپ میں ایک الارم سیٹ کرنے کی اجازت دیتا ہے۔ الارم گھڑی کی کچھ ایپس اس خصوصیت کو نافذ نہیں کر سکتی ہیں۔"</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"صوتی میلز لکھیں"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"ایپ کو پیغامات میں ترمیم کرنے اور ان کو آپ کے صوتی میل ان باکس سے ہٹانے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"صوتی میل شامل کریں"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ایپ کو آپ کے صوتی میل کے ان باکس میں پیغامات شامل کرنے کی اجازت دیتا ہے۔"</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"پیکیجز کی توثیق کریں"</string>
@@ -1559,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"سسٹم"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوٹوتھ آڈیو"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"وائرلیس ڈسپلے"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"میڈیا آؤٹ پٹ"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"آلہ سے مربوط ہوں"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"اسکرین کو آلہ پر کاسٹ کریں"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"آلات تلاش کر رہا ہے…"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index c3e7f59..fb0b55fc 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Bluetooth MAP xabarlarni qabul qilish va qayta ishlash. O‘qilmagan xabarlarni kuzatish va o‘chirish."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"ishlab turgan ilovalar to‘g‘risida ma’lumot olish"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Ilovaga hozirda va so‘nggi ishga tushirilgan vazifalar haqida to‘liq ma’lumot olishiga ruxsat beradi. Bu ilovaga qurilmadagi ishlatilayotgan ilovalar haqidagi ma’lumotlarga ega bo‘lishiga ruxsat berishi mumkin."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"foydalanuvchilar o‘rtasida o‘zaro aloqa"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ilovaga qurilmadagi turli foydalanuvchilarga ta‘sir ko‘rsatadigan amallarni bajarishga ruxsat beradi. Zararli ilovalar bundan foydalanuvchilar o‘rtasidagi himoyani buzishda foydalanishi mumkin."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"foydalanuvchilar o‘rtasidagi o‘zaro aloqa uchun to‘liq litsenziya"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Ilovaga telefoningizga zaxiralangan brauzer tarixi yoki xatcho‘plarini o‘zgartirish uchun ruxsat beradi. Bu ilovaga brauzer ma’lumotlarini o‘zgartirish yoki o‘chirishga ruxsat berishi mumkin. Diqqat qiling: ushbu ruxsat uchinchi taraf brauzerlari yoki internetni ko‘rsatish qobiliyatiga ega boshqa ilovalardan talab qilinmasligi mumkin."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"signal o‘rnatish"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Ilova uyg‘otkichni sozlashi mumkin. Ba’zi soat ilovalari ushbu funksiyani qo‘llab-quvvatlamasligi mumkin."</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"ovozli pochta xabarlarini yozish"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"Ilovaga ovozli pochtangizdagi xabarlarni o‘zgartirish va o‘chirish uchun ruxsat beradi."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ovozli xat qo‘shish"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Ilova xabarlarni ovozli pochta qutingizga qo‘shishi mumkin."</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <string name="permlab_readVoicemail" msgid="8415201752589140137">"ovozli pochta xabarlarini o‘qish"</string>
+    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Ilovaga ovozli pochta xabarlaringizni o‘qish uchun ruxsat beradi."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"brauzerdagi geolokatsiya ma’lumotlariga kirish huquqini o‘zgartirish"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ilova brauzerdagi geolokatsiya ma’lumotlariga kirish sozlamalarini o‘zgartirishi mumkin. Zararli dasturlar uning yordamida joylashuv to‘g‘risidagi ma’lumotlarni boshqa istalgan veb-saytga yuborishi mumkin."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"paketlarni tekshirish"</string>
@@ -1390,10 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ilova ishonchli agentlar xizmatiga ulanishi mumkin."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Tizimni yangilash va tiklashni birgalikda amalga oshirish"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Dasturga tizimni tiklash va yangilash imkoniyatlari bilan ishlash uchun ruxsat beradi."</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"Kontentni translatsiya qilish seanslarini yaratish"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"Ilovaga kontentni translatsiya qilish seanslarini yaratish uchun ruxsat beradi. Ushbu seanslar yordamida ilovalar qurilma ekranidagi tasvirlar va audio kontentda foydalanish huquqini qo‘lga kiritadi. Oddiy ilovalar uchun talab qilinmaydi."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Masshtabni o‘zgartirish uchun ikki marta bosing"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string>
@@ -1518,20 +1516,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Tahrirlash"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Ma’lumotlardan foydalanish ogohlantirilishi"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"Trafik sarfi va sozlamalarni ko‘rish uchun bosing."</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G/3G internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"Mobil internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"Wi-Fi internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"Chegaraga yetib keldi"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G ma’lumot cheklovdan o‘tdi"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G ma’lumot cheklovdan o‘tdi"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Mob. trafik cheg-dan oshib ketdi"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi ma’lumot cheklovdan o‘tdi"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Chegaradan <xliff:g id="SIZE">%s</xliff:g> oshib ketdi."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Orqa fon ma’lumotlari cheklangan"</string>
@@ -1567,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Tizim"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Simsiz ekran"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Media chiqish"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Qurilmaga ulanish"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekrandagi tasvirni qurilmaga uzatish"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Qurilmalar izlanmoqda..."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b1c7acc..c12ef19 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Cho phép ứng dụng nhận và xử lý tin nhắn MAP qua Bluetooth. Điều này có nghĩa là ứng dụng có thể giám sát hoặc xóa tin nhắn được gửi đến thiết bị của bạn mà không hiển thị chúng cho bạn."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"truy xuất các ứng dụng đang chạy"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Cho phép ứng dụng truy xuất thông tin về các công việc đã và đang chạy gần đây. Việc này có thể cho phép ứng dụng phát hiện thông tin về những ứng dụng nào đã được sử dụng trên thiết bị."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"tương tác giữa người dùng"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Cho phép ứng dụng thực hiện hành động giữa những người dùng khác trên thiết bị. Ứng dụng độc hại có thể sử dụng quyền này để vi phạm khả năng bảo vệ giữa người dùng."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"cấp phép đầy đủ để tương tác giữa người dùng"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Hiển thị không dây"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Kết nối với thiết bị"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Truyền màn hình tới thiết bị"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Đang tìm kiếm thiết bị…"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index be51b82..d13d76c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -55,16 +55,16 @@
     <string name="passwordIncorrect" msgid="7612208839450128715">"密码不正确。"</string>
     <string name="mmiComplete" msgid="8232527495411698359">"MMI 码已完成。"</string>
     <string name="badPin" msgid="9015277645546710014">"您输入的旧 PIN 不正确。"</string>
-    <string name="badPuk" msgid="5487257647081132201">"您输入的 PUK 码不正确。"</string>
+    <string name="badPuk" msgid="5487257647081132201">"您输入的PUK码不正确。"</string>
     <string name="mismatchPin" msgid="609379054496863419">"您输入的 PIN 码不一致。"</string>
     <string name="invalidPin" msgid="3850018445187475377">"输入一个 4 至 8 位数的 PIN 码。"</string>
-    <string name="invalidPuk" msgid="8761456210898036513">"请键入至少 8 位数字的 PUK 码。"</string>
-    <string name="needPuk" msgid="919668385956251611">"已对 SIM 卡进行 PUK 码锁定。键入 PUK 码将其解锁。"</string>
-    <string name="needPuk2" msgid="4526033371987193070">"输入 PUK2 码以解锁 SIM 卡。"</string>
-    <string name="enablePin" msgid="209412020907207950">"失败,请启用 SIM/RUIM 卡锁定设置。"</string>
+    <string name="invalidPuk" msgid="8761456210898036513">"请输入至少8位数字的PUK码。"</string>
+    <string name="needPuk" msgid="919668385956251611">"已对SIM卡进行PUK码锁定。键入PUK码将其解锁。"</string>
+    <string name="needPuk2" msgid="4526033371987193070">"输入PUK2码以解锁SIM卡。"</string>
+    <string name="enablePin" msgid="209412020907207950">"失败,请启用SIM/RUIM 卡锁定设置。"</string>
   <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将被锁定。"</item>
-    <item quantity="other" msgid="7530597808358774740">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将被锁定。"</item>
+    <item quantity="one" msgid="6596245285809790142">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将被锁定。"</item>
+    <item quantity="other" msgid="7530597808358774740">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将被锁定。"</item>
   </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -287,17 +287,21 @@
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"发送“通过信息回复”事件"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"允许应用向其他信息应用发送请求,以便处理来电的“通过信息回复”事件。"</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"读取您的讯息(短信或彩信)"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"允许该应用读取您平板电脑或 SIM 卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string>
-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"允许该应用读取您手机或 SIM 卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"允许该应用读取您平板电脑或SIM卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"允许该应用读取您手机或SIM卡上存储的短信。此权限可让该应用读取所有短信,而不考虑短信内容或机密性。"</string>
     <string name="permlab_writeSms" msgid="3216950472636214774">"编辑您的讯息(短信或彩信)"</string>
-    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"允许应用对平板电脑或 SIM 卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string>
-    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"允许应用对手机或 SIM 卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string>
+    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"允许应用对平板电脑或SIM卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string>
+    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"允许应用对手机或SIM卡上存储的短信执行写入操作。恶意应用可能会删除您的短信。"</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"接收讯息 (WAP)"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"允许该应用接收和处理 WAP 消息。此权限包括监视发送给您的消息或删除发送给您的消息而不向您显示的功能。"</string>
     <string name="permlab_receiveBluetoothMap" msgid="7593811487142360528">"接收蓝牙信息(MAP)"</string>
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"允许此应用接收和处理蓝牙MAP信息。这意味着,该应用可能会监视发送或到您设备的信息,在您阅读发送到您设备的信息之前擅自删除信息。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"检索正在运行的应用"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"允许该应用检索近期运行的和当前正在运行的任务的相关信息。此权限可让该应用了解设备上使用了哪些应用。"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"用户间互动"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允许该应用在设备上跨多个用户执行操作。恶意应用可能会借此破坏用户之间的保护措施。"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"完全允许在用户之间进行互动"</string>
@@ -870,8 +874,8 @@
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"其他"</string>
     <string name="quick_contacts_not_available" msgid="746098007828579688">"找不到可用来查看此联系人的应用。"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"请输入 PUK 码和新的 PIN 码"</string>
-    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK 码"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"请输入PUK码和新的PIN码"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK码"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"新的 PIN 码"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"触摸可输入密码"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"输入密码以解锁"</string>
@@ -894,13 +898,13 @@
     <string name="lockscreen_charged" msgid="321635745684060624">"充电完成"</string>
     <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"连接您的充电器。"</string>
-    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有 SIM 卡"</string>
-    <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板电脑中没有 SIM 卡。"</string>
-    <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手机中无 SIM 卡"</string>
-    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"请插入 SIM 卡"</string>
-    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM 卡缺失或无法读取。请插入 SIM 卡。"</string>
-    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM 卡无法使用。"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的 SIM 卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string>
+    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有SIM卡"</string>
+    <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板电脑中没有SIM卡。"</string>
+    <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手机中无SIM卡"</string>
+    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"请插入SIM卡"</string>
+    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM卡缺失或无法读取。请插入SIM卡。"</string>
+    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM卡无法使用。"</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"您的SIM卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张SIM卡。"</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"“上一曲目”按钮"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"“下一曲目”按钮"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"“暂停”按钮"</string>
@@ -908,10 +912,10 @@
     <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"“停止”按钮"</string>
     <string name="emergency_calls_only" msgid="6733978304386365407">"只能拨打紧急呼救电话"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"网络已锁定"</string>
-    <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 卡已用 PUK 码锁定"</string>
+    <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM卡已用PUK码锁定。"</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"请参阅《用户指南》或与客服人员联系。"</string>
-    <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 卡被锁定"</string>
-    <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"正在解锁 SIM 卡..."</string>
+    <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM卡被锁定"</string>
+    <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"正在解锁SIM卡..."</string>
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
@@ -1006,16 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"允许该应用修改您手机上存储的浏览器历史记录或浏览器书签。此权限可让该应用清除或修改浏览器数据。请注意:此权限可能不适用于第三方浏览器或具备网页浏览功能的其他应用。"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"设置闹钟"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"允许应用在已安装的闹钟应用中设置闹钟。有些闹钟应用可能无法实现此功能。"</string>
-    <!-- no translation found for permlab_writeVoicemail (7309899891683938100) -->
-    <skip />
-    <!-- no translation found for permdesc_writeVoicemail (6592572839715924830) -->
-    <skip />
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"写入语音邮件"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"允许应用修改和移除您语音信箱中的语音邮件。"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"添加语音邮件"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允许应用向您的语音信箱收件箱添加邮件。"</string>
-    <!-- no translation found for permlab_readVoicemail (8415201752589140137) -->
-    <skip />
-    <!-- no translation found for permdesc_readVoicemail (8926534735321616550) -->
-    <skip />
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"验证软件包"</string>
@@ -1291,10 +1291,10 @@
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"之后,您可以在“设置”&gt;“应用”中更改此设置"</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"始终允许"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"永不允许"</string>
-    <string name="sim_removed_title" msgid="6227712319223226185">"已移除 SIM 卡"</string>
+    <string name="sim_removed_title" msgid="6227712319223226185">"已移除SIM卡"</string>
     <string name="sim_removed_message" msgid="5450336489923274918">"您需要先插入有效的SIM卡再重新开机,然后才能使用移动网络。"</string>
     <string name="sim_done_button" msgid="827949989369963775">"完成"</string>
-    <string name="sim_added_title" msgid="3719670512889674693">"已添加 SIM 卡"</string>
+    <string name="sim_added_title" msgid="3719670512889674693">"已添加SIM卡"</string>
     <string name="sim_added_message" msgid="7797975656153714319">"请重新启动您的设备,以便使用移动网络。"</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"重新启动"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"设置时间"</string>
@@ -1329,7 +1329,7 @@
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"作为相机连接"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"作为安装程序连接"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已连接到USB配件"</string>
-    <string name="usb_notification_message" msgid="2290859399983720271">"触摸可显示其他 USB 选项。"</string>
+    <string name="usb_notification_message" msgid="2290859399983720271">"触摸可显示其他USB选项。"</string>
     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"格式化 USB 存储设备吗?"</string>
     <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"要格式化 SD 卡吗?"</string>
     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"您的 USB 存储设备中存储的所有文件都将清除。该操作无法撤消!"</string>
@@ -1390,10 +1390,8 @@
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允许应用绑定至信任的代理服务。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"与更新和恢复系统互动"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"允许应用与恢复系统和系统更新互动。"</string>
-    <!-- no translation found for permlab_createMediaProjection (4941338725487978112) -->
-    <skip />
-    <!-- no translation found for permdesc_createMediaProjection (1284530992706219702) -->
-    <skip />
+    <string name="permlab_createMediaProjection" msgid="4941338725487978112">"创建媒体投影会话"</string>
+    <string name="permdesc_createMediaProjection" msgid="1284530992706219702">"允许应用创建媒体投影会话。这些会话可让应用截取显示内容和音频内容。普通应用绝不需要此权限。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"触摸两次可进行缩放控制"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"无法添加小部件。"</string>
     <string name="ime_action_go" msgid="8320845651737369027">"开始"</string>
@@ -1518,20 +1516,14 @@
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"流量警告"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"触摸可查看使用情况和设置。"</string>
-    <!-- no translation found for data_usage_3g_limit_title (4462365924791862301) -->
-    <skip />
-    <!-- no translation found for data_usage_4g_limit_title (7476424187522765328) -->
-    <skip />
-    <!-- no translation found for data_usage_mobile_limit_title (3393439305227911006) -->
-    <skip />
-    <!-- no translation found for data_usage_wifi_limit_title (3461968509557554571) -->
-    <skip />
-    <!-- no translation found for data_usage_limit_body (6131350187562939365) -->
-    <skip />
+    <string name="data_usage_3g_limit_title" msgid="4462365924791862301">"2G-3G数据网络已关闭"</string>
+    <string name="data_usage_4g_limit_title" msgid="7476424187522765328">"4G数据网络已关闭"</string>
+    <string name="data_usage_mobile_limit_title" msgid="3393439305227911006">"移动数据网络已关闭"</string>
+    <string name="data_usage_wifi_limit_title" msgid="3461968509557554571">"WLAN数据网络已关闭"</string>
+    <string name="data_usage_limit_body" msgid="6131350187562939365">"已达到上限"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"已超出 2G-3G 数据流量限制"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"已超出 4G 数据使用上限"</string>
-    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
-    <skip />
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"已超出移动数据流量上限"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"超出了 WLAN 数据流量上限"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"超出规定上限 <xliff:g id="SIZE">%s</xliff:g>。"</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"后台流量受限制"</string>
@@ -1553,7 +1545,7 @@
     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"查看全部"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"选择活动"</string>
     <string name="share_action_provider_share_with" msgid="5247684435979149216">"分享方式"</string>
-    <string name="list_delimeter" msgid="3975117572185494152">"、 "</string>
+    <string name="list_delimeter" msgid="3975117572185494152">", "</string>
     <string name="sending" msgid="3245653681008218030">"正在发送..."</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"要启动浏览器吗?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string>
@@ -1567,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系统"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"无线显示"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"连接到设备"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"将屏幕投射到设备上"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜索设备…"</string>
@@ -1595,17 +1588,17 @@
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%1$d</xliff:g> 秒后重试。"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string>
-    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入 SIM PIN"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入SIM卡PIN码"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"输入密码"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡已被停用,需要输入 PUK 码才能继续使用。有关详情,请联系您的运营商。"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM卡已被停用,需要输入PUK码才能继续使用。有关详情,请联系您的运营商。"</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"请输入所需 PIN 码"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"请确认所需 PIN 码"</string>
-    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁 SIM 卡..."</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁SIM卡..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 码有误。"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK码应包含8位数字。"</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的 PUK 码。如果尝试错误次数过多,SIM 卡将永久停用。"</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 码不匹配"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的 Google 帐户。"</string>
@@ -1758,9 +1751,9 @@
     <string name="lock_to_app_description" msgid="2800403592608529611">"“单应用模式”功能会锁定屏幕,使其只显示一个应用。{\n\n要退出,请触摸并按住“最近用过的应用”按钮。"</string>
     <string name="lock_to_app_negative" msgid="2259143719362732728">"不用了"</string>
     <string name="lock_to_app_positive" msgid="7085139175671313864">"启动"</string>
-    <string name="lock_to_app_start" msgid="3074665051586318340">"开启单应用模式"</string>
-    <string name="lock_to_app_exit" msgid="8967089657201849300">"不再使用单应用模式"</string>
-    <string name="lock_to_app_use_screen_lock" msgid="1434584309048590886">"退出前要求%1$s"</string>
+    <string name="lock_to_app_start" msgid="3074665051586318340">"已开启单应用模式"</string>
+    <string name="lock_to_app_exit" msgid="8967089657201849300">"已退出单应用模式"</string>
+    <string name="lock_to_app_use_screen_lock" msgid="1434584309048590886">"退出前要求输入%1$s"</string>
     <string name="lock_to_app_unlock_pin" msgid="7908385370846820001">"PIN码"</string>
     <string name="lock_to_app_unlock_pattern" msgid="7763071104790758405">"解锁图案"</string>
     <string name="lock_to_app_unlock_password" msgid="795224196583495868">"密码"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 8f7b5a0..366ff24 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"允許應用程式接收和處理藍牙 MAP 訊息。這項設定可讓應用程式監控傳送至您裝置的訊息,或在您閱讀訊息前擅自刪除訊息。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"擷取執行中的應用程式"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"允許應用程式擷取有關目前和最近執行的工作的資訊。如此一來,應用程式或可找出裝置上所使用應用程式的相關資訊。"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"與其他用戶互動"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允許應用程式對裝置上的不同用戶執行各種操作。請注意,惡意應用程式可能藉此破壞各用戶之間的保護機制。"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"全面授權與其他用戶互動"</string>
@@ -1006,12 +1010,12 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"允許應用程式修改手機上儲存的瀏覽器記錄或書籤。如此一來,應用程式或可清除或修改瀏覽器資料。注意:這項權限可能不適用於第三方瀏覽器或其他具備網頁瀏覽功能的應用程式。"</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"設定鬧鐘"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"允許應用程式在安裝的鬧鐘應用程式中設定鬧鐘,某些鬧鐘應用程式可能沒有這項功能。"</string>
-    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"寫入語音留言"</string>
-    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"允許應用程式修改及移除語音留言收件匣中的訊息。"</string>
+    <string name="permlab_writeVoicemail" msgid="7309899891683938100">"寫入留言訊息"</string>
+    <string name="permdesc_writeVoicemail" msgid="6592572839715924830">"允許應用程式修改和移除留言信箱中的訊息。"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"新增留言"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件箱。"</string>
-    <string name="permlab_readVoicemail" msgid="8415201752589140137">"讀取語音留言"</string>
-    <string name="permdesc_readVoicemail" msgid="8926534735321616550">"允許應用程式讀取您的語音留言。"</string>
+    <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="permlab_packageVerificationAgent" msgid="5568139100645829117">"驗證套件"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音頻"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"連接裝置"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"在裝置上放送螢幕"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置…"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index fbffc99..32d6114 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"允許應用程式接收及處理藍牙 MAP 訊息。這項設定可讓應用程式監控傳送至您裝置的訊息,或在您閱讀訊息前主動刪除訊息。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"擷取執行中的應用程式"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"允許應用程式擷取最近執行工作的資訊。這項設定可讓應用程式找出裝置所用程式的相關資訊。"</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"對所有使用者執行各種動作"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允許應用程式對裝置上的所有使用者執行各種動作。請注意,惡意應用程式可能利用此功能侵害使用者之間的保護機制。"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"完整授權對所有使用者執行各種動作"</string>
@@ -1181,11 +1185,11 @@
     <string name="whichApplication" msgid="4533185947064773386">"選擇要使用的應用程式"</string>
     <string name="whichApplicationNamed" msgid="8260158865936942783">"完成操作需使用 %1$s"</string>
     <string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟工具"</string>
-    <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用 %1$s 開啟"</string>
+    <string name="whichViewApplicationNamed" msgid="2286418824011249620">"透過 %1$s 開啟"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"選擇編輯工具"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
-    <string name="whichSendApplication" msgid="6902512414057341668">"選擇分享對象"</string>
-    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"與 %1$s 共用"</string>
+    <string name="whichSendApplication" msgid="6902512414057341668">"選擇分享工具"</string>
+    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"透過 %1$s 分享"</string>
     <string name="whichHomeApplication" msgid="4616420172727326782">"選取主螢幕應用程式"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"設為預設應用程式。"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"前往 [系統設定] &gt; [應用程式] &gt; [下載] 清除預設值。"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"連線至裝置"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"將螢幕投放到裝置上"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置..."</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 7f4e78b..bd3cc3f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -298,6 +298,10 @@
     <string name="permdesc_receiveBluetoothMap" msgid="8656755936919466345">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-Bluetooth MAP. Lokhu kusho ukuthi uhlelo lokusebenza lingakwazi ukugada noma ukususa imilayezo ethunyelwa kwidivayisi yakho ngaphandle kokukubonisa yona."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"thola izinhlelo zokusebenza ezisebenzayo"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Ivumela uhlelo lokusebenza ukubuyisa ulwazi mayelana nemisebenzi yamanje neyakamuva. Lokhu kungavumela uhlelo lokusebenza ukuthola ulwazi mayelana nokuthi iziphi izinhlelo zokusebenza ezisetshenziswa kudivayisi."</string>
+    <!-- no translation found for permlab_startTasksFromRecents (8990073877885690623) -->
+    <skip />
+    <!-- no translation found for permdesc_startTasksFromRecents (7382133554871222235) -->
+    <skip />
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ihlanganyela phakathi kwabasebenzisi"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ivumela uhlelo lokusebenza ukwenza izenzo kubasebenzisi bonke kudivayisi. Izinhlelo zokusebenza ezingalungile zingasebenzisa lokhu ukwephula ukuvikela phakathi kwabasebenzisi."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ilayisensi egcwele yokuhlanganyela kubasebenzisi"</string>
@@ -1555,7 +1559,8 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Isistimu"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Ukubonisa okungenazintambo"</string>
-    <string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string>
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Xhuma kudivayisi"</string>
     <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lingisa isikrini kudivayisi"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Isesha amadivayisi…"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 73c6a67..19d58c7 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1847,6 +1847,9 @@
 
         <!-- Elevation to use for the window. -->
         <attr name="windowElevation" format="dimension" />
+
+        <!-- Whether to clip window content to the outline of the window background. -->
+        <attr name="windowClipToOutline" format="boolean" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -3755,6 +3758,8 @@
         <attr name="shadowRadius" format="float" />
         <!-- Elegant text height, especially for less compacted complex script text. -->
         <attr name="elegantTextHeight" format="boolean" />
+        <!-- Text letter-spacing. -->
+        <attr name="letterSpacing" format="float" />
     </declare-styleable>
     <declare-styleable name="TextClock">
         <!-- Specifies the formatting pattern used to show the time and/or date
@@ -4048,6 +4053,8 @@
         <attr name="textAllCaps" />
         <!-- Elegant text height, especially for less compacted complex script text. -->
         <attr name="elegantTextHeight" />
+        <!-- Text letter-spacing. -->
+        <attr name="letterSpacing" />
     </declare-styleable>
     <declare-styleable name="TextViewAppearance">
         <!-- Base text color, typeface, size, and style. -->
@@ -5112,24 +5119,16 @@
         <!-- Indicates if the drawable needs to be mirrored when its layout direction is
              RTL (right-to-left). -->
         <attr name="autoMirrored" />
-    </declare-styleable>
-
-    <!-- Define the virtual size of the drawing surface paths will draw to. -->
-    <declare-styleable name="VectorDrawableViewport">
+        <!-- The intrinsic width of the Vector Drawable. -->
+        <attr name="width" />
+        <!-- The intrinsic height of the Vector Drawable. -->
+        <attr name="height" />
         <!-- The width of the canvas the drawing is on. -->
         <attr name="viewportWidth" format="float"/>
         <!-- The height of the canvas the drawing is on. -->
         <attr name="viewportHeight" format="float"/>
     </declare-styleable>
 
-    <!-- Define the size of the drawable -->
-    <declare-styleable name="VectorDrawableSize">
-        <!-- Width of the Vector Drawable. -->
-        <attr name="width" />
-        <!-- Height of the Vector Drawable. -->
-        <attr name="height" />
-    </declare-styleable>
-
     <!-- Defines the group used in VectorDrawables. -->
     <declare-styleable name="VectorDrawableGroup">
         <!-- The Name of this group -->
@@ -5161,9 +5160,9 @@
         <!-- The opacity of a path stroke -->
         <attr name="strokeOpacity" format="float" />
         <!-- The color to stroke the path if not defined implies no stroke-->
-        <attr name="stroke" format="color" />
+        <attr name="strokeColor" format="color" />
         <!-- The color to fill the path if not defined implies no fill-->
-        <attr name="fill" format="color" />
+        <attr name="fillColor" format="color" />
         <!-- The level of opacity of the filled area of the path -->
         <attr name="fillOpacity" format="float" />
         <!-- The specification of the operations that define the path  -->
@@ -5174,7 +5173,7 @@
         <attr name="trimPathEnd" format="float" />
         <!-- Shift trim region (allows visible region to include the start and end) from 0 to 1  -->
         <attr name="trimPathOffset" format="float" />
-        <!-- Path will set the current clip path -->
+        <!-- TODO: Remove this. Path will set the current clip path -->
         <attr name="clipToPath" format="boolean" />
         <!-- sets the linecap for a stroked path -->
         <attr name="strokeLineCap" format="enum">
@@ -5192,6 +5191,14 @@
         <attr name="strokeMiterLimit" format="float"/>
     </declare-styleable>
 
+    <!-- Defines the clip path used in VectorDrawables. -->
+    <declare-styleable name="VectorDrawableClipPath">
+        <!-- The Name of this path -->
+        <attr name="name" />
+        <!-- The specification of the operations that define the path  -->
+        <attr name="pathData"/>
+    </declare-styleable>
+
     <!-- ========================== -->
     <!--   AnimatedVectorDrawable class   -->
     <!-- ========================== -->
@@ -5451,14 +5458,14 @@
          described here. -->
     <declare-styleable name="Slide">
         <attr name="slideEdge">
+            <!-- Slide to and from the left edge of the Scene. -->
+            <enum name="left" value="0x03" />
+            <!-- Slide to and from the top edge of the Scene. -->
+            <enum name="top" value="0x30" />
+            <!-- Slide to and from the right edge of the Scene. -->
+            <enum name="right" value="0x05" />
             <!-- Slide to and from the bottom edge of the Scene. -->
-            <enum name="left" value="0" />
-            <!-- Slide to and from the bottom edge of the Scene. -->
-            <enum name="top" value="1" />
-            <!-- Slide to and from the bottom edge of the Scene. -->
-            <enum name="right" value="2" />
-            <!-- Slide to and from the bottom edge of the Scene. -->
-            <enum name="bottom" value="3" />
+            <enum name="bottom" value="0x50" />
         </attr>
     </declare-styleable>
 
@@ -6807,16 +6814,18 @@
     <!-- Use <code>voice-enrollment-application</code>
          as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
          by the enrollment application.
-         Described here are the attributes that can be included in that tag. -->
+         Described here are the attributes that can be included in that tag.
+         @hide
+         @SystemApi -->
     <declare-styleable name="VoiceEnrollmentApplication">
-        <!-- A globally unique ID for the keyphrase. -->
+        <!-- A globally unique ID for the keyphrase. @hide @SystemApi -->
         <attr name="searchKeyphraseId" format="integer" />
-        <!-- The actual keyphrase/hint text, or empty if not keyphrase dependent. -->
+        <!-- The actual keyphrase/hint text, or empty if not keyphrase dependent. @hide @SystemApi -->
         <attr name="searchKeyphrase" format="string" />
         <!-- A comma separated list of java locales that are supported for this keyphrase,
-             or empty if not locale dependent. -->
+             or empty if not locale dependent. @hide @SystemApi -->
         <attr name="searchKeyphraseSupportedLocales" format="string" />
-        <!-- Flags for supported recognition modes. -->
+        <!-- Flags for supported recognition modes. @hide @SystemApi -->
         <attr name="searchKeyphraseRecognitionFlags">
             <flag name="none" value="0" />
             <flag name="voiceTrigger" value="0x1" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7311a60..c268d97 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1285,6 +1285,19 @@
         <attr name="required" format="boolean" />
     </declare-styleable>
 
+    <!-- The <code>feature-group</code> tag specifies
+         a set of one or more <code>uses-feature</code> elements that
+         the application can utilize. An application uses multiple
+         <code>feature-group</code> sets to indicate that it can support
+         different combinations of features.
+
+         <p>This appears as a child tag of the root
+         {@link #AndroidManifest manifest} tag. -->
+    <declare-styleable name="AndroidManifestFeatureGroup">
+        <!-- The human-readable name of the feature group. -->
+        <attr name="label" />
+    </declare-styleable>
+
     <!-- The <code>uses-sdk</code> tag describes the SDK features that the
          containing package must be running on to operate correctly.
          
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0954ddf..7f160e8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1588,6 +1588,9 @@
     <!-- default device has recents property -->
     <bool name="config_hasRecents">true</bool>
 
+    <!-- default window ShowCircularMask property -->
+    <bool name="config_windowShowCircularMask">false</bool>
+
     <!-- Defines the default set of global actions. Actions may still be disabled or hidden based
          on the current state of the device.
          Each item must be one of the following strings:
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 77b115b..afe180f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -384,4 +384,9 @@
     <dimen name="immersive_mode_cling_width">-1px</dimen>
 
     <dimen name="resolver_max_width">480dp</dimen>
+
+     <!-- Size of the offset applied to the position of the circular mask. This is only
+     used on circular displays. In the case where there is no "chin", this will default
+     to 0 -->
+     <dimen name="circular_display_mask_offset">0px</dimen>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a6e85e9..0a87d0d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2119,9 +2119,9 @@
   <public type="attr" name="viewportWidth" />
   <public type="attr" name="viewportHeight" />
   <public type="attr" name="fillOpacity" />
-  <public type="attr" name="fill" />
+  <public type="attr" name="fillColor" />
   <public type="attr" name="pathData" />
-  <public type="attr" name="stroke" />
+  <public type="attr" name="strokeColor" />
   <public type="attr" name="strokeOpacity" />
   <public type="attr" name="strokeWidth" />
   <public type="attr" name="trimPathStart" />
@@ -2268,6 +2268,7 @@
   <public type="attr" name="checkMarkTintMode" />
   <public type="attr" name="popupTheme" />
   <public type="attr" name="toolbarStyle" />
+  <public type="attr" name="windowClipToOutline" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b41e37c..c6ee89f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3872,6 +3872,11 @@
     <!-- Description of an application permission that lets it create media projection sessions. -->
     <string name="permdesc_createMediaProjection">Allows an application to create media projection sessions. These sessions can provide applications the ability to capture display and audio contents. Should never be needed by normal apps.</string>
 
+    <!-- Title of an application permission that lets it read install sessions. -->
+    <string name="permlab_readInstallSessions">Read install sessions</string>
+    <!-- Description of an application permission that lets it read install sessions. -->
+    <string name="permdesc_readInstallSessions">Allows an application to read install sessions. This allows it to see details about active package installations.</string>
+
     <!-- Shown in the tutorial for tap twice for zoom control. -->
     <string name="tutorial_double_tap_to_zoom_message_short">Touch twice for zoom control</string>
 
@@ -3926,6 +3931,11 @@
     <string name="permission_request_notification_title">Permission requested</string>
     <string name="permission_request_notification_with_subtitle">Permission requested\nfor account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g>.</string>
 
+    <!-- Message to show when an intent automatically switches users into the personal profile. -->
+    <string name="forward_intent_to_owner">You\'re using this app in your personal space</string>
+    <!-- Message to show when an intent automatically switches users into a work profile. -->
+    <string name="forward_intent_to_work">You\'re using this app in your work space</string>
+
     <!-- Label to show for a service that is running because it is an input method. -->
     <string name="input_method_binding_label">Input method</string>
     <!-- Label to show for a service that is running because it is a sync adapter. -->
@@ -4310,8 +4320,9 @@
     <!-- Description of a wireless display route. [CHAR LIMIT=50] -->
     <string name="wireless_display_route_description">Wireless display</string>
 
-    <!-- Content description of a MediaRouteButton for accessibility support -->
-    <string name="media_route_button_content_description">Media output</string>
+    <!-- Content description of a MediaRouteButton for accessibility support.
+        Cast is the standard android verb for sending content to a remote device. [CHAR LIMIT=50] -->
+    <string name="media_route_button_content_description">Cast</string>
 
     <!-- Title of the media route chooser dialog. [CHAR LIMIT=40] -->
     <string name="media_route_chooser_title">Connect to device</string>
@@ -4487,7 +4498,7 @@
     <!-- Message shown in dialog when user is attempting to set the music volume above the
     recommended maximum level for headphones -->
     <string name="safe_media_volume_warning" product="default">
-       "Raise volume above recommended level?\nListening at high volume for long periods may damage your hearing."
+       "Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."
     </string>
 
     <!-- Text spoken when the user is performing a gesture that will enable accessibility. [CHAR LIMIT=none] -->
@@ -4502,8 +4513,8 @@
     <string name="owner_name" msgid="3879126011135546571">Owner</string>
     <!-- Error message title [CHAR LIMIT=35] -->
     <string name="error_message_title">Error</string>
-    <!-- Message informing user that app is not permitted to access accounts. [CHAR LIMIT=none] -->
-    <string name="app_no_restricted_accounts">This app doesn\'t support accounts for restricted profiles</string>
+    <!-- Message informing user that the change was disallowed by an administrator. [CHAR LIMIT=none] -->
+    <string name="error_message_change_not_allowed">This change isn\'t allowed by your administrator</string>
     <!-- Message informing user that the requested activity could not be found [CHAR LIMIT=none] -->
     <string name="app_not_found">No application found to handle this action</string>
     <string name="revoke">Revoke</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c324e93..30209e9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -16,7 +16,6 @@
 */
 -->
 <resources>
-
   <!-- We don't want to publish private symbols in android.R as part of the
        SDK.  Instead, put them here. -->
   <private-symbols package="com.android.internal" />
@@ -290,6 +289,7 @@
   <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
   <java-symbol type="bool" name="config_windowIsRound" />
   <java-symbol type="bool" name="config_hasRecents" />
+  <java-symbol type="bool" name="config_windowShowCircularMask" />
 
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
@@ -350,6 +350,7 @@
   <java-symbol type="dimen" name="notification_title_text_size" />
   <java-symbol type="dimen" name="notification_subtext_size" />
   <java-symbol type="dimen" name="immersive_mode_cling_width" />
+  <java-symbol type="dimen" name="circular_display_mask_offset" />
 
   <java-symbol type="string" name="add_account_button_label" />
   <java-symbol type="string" name="addToDictionary" />
@@ -876,7 +877,7 @@
   <java-symbol type="string" name="config_customResolverActivity" />
   <java-symbol type="string" name="config_appsAuthorizedForSharedAccounts" />
   <java-symbol type="string" name="error_message_title" />
-  <java-symbol type="string" name="app_no_restricted_accounts" />
+  <java-symbol type="string" name="error_message_change_not_allowed" />
   <java-symbol type="string" name="action_bar_home_description_format" />
   <java-symbol type="string" name="action_bar_home_subtitle_description_format" />
   <java-symbol type="string" name="wireless_display_route_description" />
@@ -1432,6 +1433,8 @@
   <java-symbol type="style" name="Animation.LockScreen" />
   <java-symbol type="style" name="Theme.Dialog.RecentApplications" />
   <java-symbol type="style" name="Theme.ExpandedMenu" />
+  <java-symbol type="string" name="forward_intent_to_owner" />
+  <java-symbol type="string" name="forward_intent_to_work" />
 
   <!-- From services -->
   <java-symbol type="anim" name="screen_rotate_0_enter" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 0d4a2bf..aea72c1 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -169,6 +169,7 @@
 
         <!-- Window attributes -->
         <item name="windowBackground">@drawable/screen_background_selector_dark</item>
+        <item name="windowClipToOutline">false</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
@@ -473,6 +474,8 @@
          <p>This is designed for API level 10 and lower.</p>-->
     <style name="Theme.Light">
         <item name="windowBackground">@drawable/screen_background_selector_light</item>
+        <item name="windowClipToOutline">false</item>
+
         <item name="colorBackground">@color/background_light</item>
         <item name="colorForeground">@color/bright_foreground_light</item>
         <item name="colorForegroundInverse">@color/bright_foreground_light_inverse</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 741ffe6..f2233e0 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -146,6 +146,7 @@
 
         <!-- Window attributes -->
         <item name="windowBackground">@color/background_material_dark</item>
+        <item name="windowClipToOutline">true</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
@@ -512,6 +513,7 @@
 
         <!-- Window attributes -->
         <item name="windowBackground">@color/background_material_light</item>
+        <item name="windowClipToOutline">true</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
new file mode 100644
index 0000000..5e451ca
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.le;
+
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for {@link AdvertiseData}.
+ * <p>
+ * To run the test, use adb shell am instrument -e class 'android.bluetooth.le.AdvertiseDataTest' -w
+ * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class AdvertiseDataTest extends TestCase {
+
+    private AdvertiseData.Builder mAdvertiseDataBuilder;
+
+    @Override
+    protected void setUp() throws Exception {
+        mAdvertiseDataBuilder = new AdvertiseData.Builder();
+    }
+
+    @SmallTest
+    public void testEmptyData() {
+        Parcel parcel = Parcel.obtain();
+        AdvertiseData data = mAdvertiseDataBuilder.build();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AdvertiseData dataFromParcel =
+                AdvertiseData.CREATOR.createFromParcel(parcel);
+        assertEquals(data, dataFromParcel);
+    }
+
+    @SmallTest
+    public void testEmptyServiceUuid() {
+        Parcel parcel = Parcel.obtain();
+        AdvertiseData data = mAdvertiseDataBuilder.setIncludeDeviceName(true).build();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AdvertiseData dataFromParcel =
+                AdvertiseData.CREATOR.createFromParcel(parcel);
+        assertEquals(data, dataFromParcel);
+    }
+
+    @SmallTest
+    public void testEmptyManufacturerData() {
+        Parcel parcel = Parcel.obtain();
+        int manufacturerId = 50;
+        byte[] manufacturerData = new byte[0];
+        AdvertiseData data =
+                mAdvertiseDataBuilder.setIncludeDeviceName(true)
+                        .setManufacturerData(manufacturerId, manufacturerData).build();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AdvertiseData dataFromParcel =
+                AdvertiseData.CREATOR.createFromParcel(parcel);
+        assertEquals(data, dataFromParcel);
+    }
+
+    @SmallTest
+    public void testEmptyServiceData() {
+        Parcel parcel = Parcel.obtain();
+        ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+        byte[] serviceData = new byte[0];
+        AdvertiseData data =
+                mAdvertiseDataBuilder.setIncludeDeviceName(true)
+                        .setServiceData(uuid, serviceData).build();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AdvertiseData dataFromParcel =
+                AdvertiseData.CREATOR.createFromParcel(parcel);
+        assertEquals(data, dataFromParcel);
+    }
+
+    @SmallTest
+    public void testServiceUuid() {
+        Parcel parcel = Parcel.obtain();
+        ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+        ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+
+        AdvertiseData data =
+                mAdvertiseDataBuilder.setIncludeDeviceName(true)
+                        .addServiceUuid(uuid).addServiceUuid(uuid2).build();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AdvertiseData dataFromParcel =
+                AdvertiseData.CREATOR.createFromParcel(parcel);
+        assertEquals(data, dataFromParcel);
+    }
+
+    @SmallTest
+    public void testManufacturerData() {
+        Parcel parcel = Parcel.obtain();
+        ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+        ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+
+        int manufacturerId = 50;
+        byte[] manufacturerData = new byte[] {
+                (byte) 0xF0, 0x00, 0x02, 0x15 };
+        AdvertiseData data =
+                mAdvertiseDataBuilder.setIncludeDeviceName(true)
+                        .addServiceUuid(uuid).addServiceUuid(uuid2)
+                        .setManufacturerData(manufacturerId, manufacturerData).build();
+
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AdvertiseData dataFromParcel =
+                AdvertiseData.CREATOR.createFromParcel(parcel);
+        assertEquals(data, dataFromParcel);
+    }
+
+    @SmallTest
+    public void testServiceData() {
+        Parcel parcel = Parcel.obtain();
+        ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+        byte[] serviceData = new byte[] {
+                (byte) 0xF0, 0x00, 0x02, 0x15 };
+        AdvertiseData data =
+                mAdvertiseDataBuilder.setIncludeDeviceName(true)
+                        .setServiceData(uuid, serviceData).build();
+        data.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AdvertiseData dataFromParcel =
+                AdvertiseData.CREATOR.createFromParcel(parcel);
+        assertEquals(data, dataFromParcel);
+    }
+}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
index 25ea227..81f4baf 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
@@ -186,7 +186,6 @@
         parcel.setDataPosition(0);
         ScanFilter filterFromParcel =
                 ScanFilter.CREATOR.createFromParcel(parcel);
-        System.out.println(filterFromParcel);
         assertEquals(filter, filterFromParcel);
     }
 }
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
index e259bcc..ccdd90a 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
@@ -27,8 +27,7 @@
 /**
  * Unit test cases for {@link ScanRecord}.
  * <p>
- * To run this test, use adb shell am instrument -e class
- * 'android.bluetooth.ScanRecordTest' -w
+ * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanRecordTest' -w
  * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
  */
 public class ScanRecordTest extends TestCase {
@@ -54,13 +53,13 @@
         assertEquals("Ped", data.getDeviceName());
         assertEquals(-20, data.getTxPowerLevel());
 
-        assertEquals(224, data.getManufacturerId());
+        assertEquals(0x00e0, data.getManufacturerId());
         assertArrayEquals(new byte[] {
-                (byte) 0xe0, 0x00, 0x02, 0x15 }, data.getManufacturerSpecificData());
+                0x02, 0x15 }, data.getManufacturerSpecificData());
 
         assertEquals(uuid2, data.getServiceDataUuid());
         assertArrayEquals(new byte[] {
-                0x0b, 0x11, 0x50, 0x64 }, data.getServiceData());
+                0x50, 0x64 }, data.getServiceData());
     }
 
     // Assert two byte arrays are equal.
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java
new file mode 100644
index 0000000..7c42c3b
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.le;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Test for Bluetooth LE {@link ScanSettings}.
+ */
+public class ScanSettingsTest extends TestCase {
+
+    @SmallTest
+    public void testCallbackType() {
+        ScanSettings.Builder builder = new ScanSettings.Builder();
+        builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
+        builder.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH);
+        builder.setCallbackType(ScanSettings.CALLBACK_TYPE_MATCH_LOST);
+        builder.setCallbackType(
+                ScanSettings.CALLBACK_TYPE_FIRST_MATCH | ScanSettings.CALLBACK_TYPE_MATCH_LOST);
+        try {
+            builder.setCallbackType(
+                    ScanSettings.CALLBACK_TYPE_ALL_MATCHES | ScanSettings.CALLBACK_TYPE_MATCH_LOST);
+            fail("should have thrown IllegalArgumentException!");
+        } catch (IllegalArgumentException e) {
+            // nothing to do
+        }
+
+        try {
+            builder.setCallbackType(
+                    ScanSettings.CALLBACK_TYPE_ALL_MATCHES |
+                    ScanSettings.CALLBACK_TYPE_FIRST_MATCH);
+            fail("should have thrown IllegalArgumentException!");
+        } catch (IllegalArgumentException e) {
+            // nothing to do
+        }
+
+        try {
+            builder.setCallbackType(
+                    ScanSettings.CALLBACK_TYPE_ALL_MATCHES |
+                    ScanSettings.CALLBACK_TYPE_FIRST_MATCH |
+                    ScanSettings.CALLBACK_TYPE_MATCH_LOST);
+            fail("should have thrown IllegalArgumentException!");
+        } catch (IllegalArgumentException e) {
+            // nothing to do
+        }
+
+    }
+}
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
index ca68e93..3a598f2 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
@@ -295,4 +295,33 @@
         assertRotationOrder(anotherController, false /* onlyCurrentIme */,
                 switchingUnawarelatinIme_en_UK, switchUnawareJapaneseIme_ja_JP);
     }
+
+    @SmallTest
+    public void testImeSubtypeListItem() throws Exception {
+        final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>();
+        addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme",
+                Arrays.asList("en_US", "fr", "en", "en_uk", "enn", "e", "EN_US"),
+                true /* supportsSwitchingToNextInputMethod*/);
+        final ImeSubtypeListItem item_en_US = items.get(0);
+        final ImeSubtypeListItem item_fr = items.get(1);
+        final ImeSubtypeListItem item_en = items.get(2);
+        final ImeSubtypeListItem item_enn = items.get(3);
+        final ImeSubtypeListItem item_e = items.get(4);
+        final ImeSubtypeListItem item_EN_US = items.get(5);
+
+        assertTrue(item_en_US.mIsSystemLocale);
+        assertFalse(item_fr.mIsSystemLocale);
+        assertFalse(item_en.mIsSystemLocale);
+        assertFalse(item_en.mIsSystemLocale);
+        assertFalse(item_enn.mIsSystemLocale);
+        assertFalse(item_e.mIsSystemLocale);
+        assertFalse(item_EN_US.mIsSystemLocale);
+
+        assertTrue(item_en_US.mIsSystemLanguage);
+        assertFalse(item_fr.mIsSystemLanguage);
+        assertTrue(item_en.mIsSystemLanguage);
+        assertFalse(item_enn.mIsSystemLocale);
+        assertFalse(item_e.mIsSystemLocale);
+        assertFalse(item_EN_US.mIsSystemLocale);
+    }
 }
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 9f6b64c..80fb1fd 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -47,14 +47,8 @@
     DroidSans-Bold.ttf
 
 ################################
-# On space-constrained devices, we include a subset of fonts:
-ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-
-droidsans_fallback_src := DroidSansFallback.ttf
-
-else  # !SMALLER_FONT_FOOTPRINT
-
-droidsans_fallback_src := DroidSansFallbackFull.ttf
+# Do not include Motoya on space-constrained devices
+ifneq ($(SMALLER_FONT_FOOTPRINT),true)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := MTLmr3m.ttf
@@ -65,24 +59,44 @@
 include $(BUILD_PREBUILT)
 extra_font_files += MTLmr3m.ttf
 
-endif  # SMALLER_FONT_FOOTPRINT
+endif  # !SMALLER_FONT_FOOTPRINT
 
 ################################
+# Use DroidSansMono to hang extra_font_files on
+include $(CLEAR_VARS)
+LOCAL_MODULE := DroidSansMono.ttf
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
+LOCAL_REQUIRED_MODULES := $(extra_font_files)
+include $(BUILD_PREBUILT)
+extra_font_files :=
+
+################################
+# Include DroidSansFallback only on non-EXTENDED_FONT_FOOTPRINT builds
+ifneq ($(EXTENDED_FONT_FOOTPRINT),true)
+
+# Include a subset of DroidSansFallback on SMALLER_FONT_FOOTPRINT build
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+droidsans_fallback_src := DroidSansFallback.ttf
+else  # !SMALLER_FONT_FOOTPRINT
+droidsans_fallback_src := DroidSansFallbackFull.ttf
+endif  # SMALLER_FONT_FOOTPRINT
+
 include $(CLEAR_VARS)
 LOCAL_MODULE := DroidSansFallback.ttf
 LOCAL_SRC_FILES := $(droidsans_fallback_src)
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-LOCAL_REQUIRED_MODULES := $(extra_font_files)
 include $(BUILD_PREBUILT)
-
-font_symlink_src :=
-font_symlink :=
 droidsans_fallback_src :=
-extra_font_files :=
+
+endif  # !EXTENDED_FONT_FOOTPRINT
+
 ################################
-# Build the rest font files as prebuilt.
+# Build the rest of font files as prebuilt.
 
 # $(1): The source file name in LOCAL_PATH.
 #       It also serves as the module name and the dest file name.
@@ -101,7 +115,6 @@
     Roboto-Bold.ttf \
     Roboto-Italic.ttf \
     Roboto-BoldItalic.ttf \
-    DroidSansMono.ttf \
     Clockopia.ttf \
     AndroidClock.ttf \
     AndroidClock_Highlight.ttf \
diff --git a/data/fonts/DroidKufi-Bold.ttf b/data/fonts/DroidKufi-Bold.ttf
deleted file mode 100644
index 650919e..0000000
--- a/data/fonts/DroidKufi-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidKufi-Regular.ttf b/data/fonts/DroidKufi-Regular.ttf
deleted file mode 100644
index af85975..0000000
--- a/data/fonts/DroidKufi-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSans-Bold.ttf b/data/fonts/DroidSans-Bold.ttf
deleted file mode 100644
index d065b64..0000000
--- a/data/fonts/DroidSans-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSans.ttf b/data/fonts/DroidSans.ttf
deleted file mode 100644
index ad1efca..0000000
--- a/data/fonts/DroidSans.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf
index 135723c..1dfcc33 100644
--- a/data/fonts/DroidSansFallbackFull.ttf
+++ b/data/fonts/DroidSansFallbackFull.ttf
Binary files differ
diff --git a/data/fonts/DroidSansJapanese.ttf b/data/fonts/DroidSansJapanese.ttf
deleted file mode 100644
index 412fa3d..0000000
--- a/data/fonts/DroidSansJapanese.ttf
+++ /dev/null
Binary files differ
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index e86d4c9..1ee6606 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -402,8 +402,7 @@
 	resolution and density of the device screen may differ, which could affect 

 	the display of strings and drawables in your UI.</p>

 

-<p>To change the locale on a device, use  the Settings application  (Home &gt;

-Menu &gt; Settings &gt; Locale &amp; text &gt; Select locale). </p>

+<p>To change the locale or language on a device, use the Settings application.</p>

 

 <h3 id="emulator">Testing on an Emulator</h3>

 

diff --git a/docs/html/preview/material/ui-widgets.jd b/docs/html/preview/material/ui-widgets.jd
index 2d29420..69b7d2d 100644
--- a/docs/html/preview/material/ui-widgets.jd
+++ b/docs/html/preview/material/ui-widgets.jd
@@ -132,7 +132,7 @@
                                                    int viewType) {
         // create a new view
         View v = LayoutInflater.from(parent.getContext())
-                               .inflate(R.layout.my_text_view, parent);
+                               .inflate(R.layout.my_text_view, parent, false);
         // set the view's size, margins, paddings and layout parameters
         ...
         ViewHolder vh = new ViewHolder(v);
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index 3ab57c1..5e004a3 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -43,7 +43,7 @@
         mTileX = tileX;
         mTileY = tileY;
         final long b = bitmap.ni();
-        native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
+        init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
     }
 
     /**
diff --git a/graphics/java/android/graphics/BlurMaskFilter.java b/graphics/java/android/graphics/BlurMaskFilter.java
index 939af52..f3064f8 100644
--- a/graphics/java/android/graphics/BlurMaskFilter.java
+++ b/graphics/java/android/graphics/BlurMaskFilter.java
@@ -25,10 +25,25 @@
 public class BlurMaskFilter extends MaskFilter {
 
     public enum Blur {
-        NORMAL(0),  //!< blur inside and outside of the original border
-        SOLID(1),   //!< include the original mask, blur outside
-        OUTER(2),   //!< just blur outside the original border
-        INNER(3);   //!< just blur inside the original border
+        /**
+         * Blur inside and outside the original border.
+         */
+        NORMAL(0),
+
+        /**
+         * Draw solid inside the border, blur outside.
+         */
+        SOLID(1),
+
+        /**
+         * Draw nothing inside the border, blur outside.
+         */
+        OUTER(2),
+
+        /**
+         * Blur inside the border, draw nothing outside.
+         */
+        INNER(3);
         
         Blur(int value) {
             native_int = value;
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index ef4b260..f3af8f6 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -52,6 +52,9 @@
         return mNativeCanvasWrapper;
     }
 
+    /** @hide */
+    public boolean isRecordingFor(Object o) { return false; }
+
     // may be null
     private Bitmap mBitmap;
 
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index d7b2071..b2adcf6 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -53,8 +53,8 @@
         mShaderA = shaderA;
         mShaderB = shaderB;
         mXferMode = mode;
-        native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
-                (mode != null) ? mode.native_instance : 0);
+        init(nativeCreate1(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
+                (mode != null) ? mode.native_instance : 0));
     }
 
     /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
@@ -69,8 +69,8 @@
         mShaderA = shaderA;
         mShaderB = shaderB;
         mPorterDuffMode = mode;
-        native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
-                mode.nativeInt);
+        init(nativeCreate2(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
+                mode.nativeInt));
     }
 
     /**
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index ab4258d..3efb9c0 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -236,17 +236,17 @@
      * Android 10-bit raw format
      * </p>
      * <p>
-     * This is a single-plane, 10-bit per pixel, densely packed, unprocessed
-     * format, usually representing raw Bayer-pattern images coming from an image
-     * sensor.
+     * This is a single-plane, 10-bit per pixel, densely packed (in each row),
+     * unprocessed format, usually representing raw Bayer-pattern images coming
+     * from an image sensor.
      * </p>
      * <p>
-     * In an image buffer with this format, starting from the first pixel, each
-     * 4 consecutive pixels are packed into 5 bytes (40 bits). Each one of the
-     * first 4 bytes contains the top 8 bits of each pixel, The fifth byte
-     * contains the 2 least significant bits of the 4 pixels, the exact layout
-     * data for each 4 consecutive pixels is illustrated below (Pi[j] stands for
-     * the jth bit of the ith pixel):
+     * In an image buffer with this format, starting from the first pixel of
+     * each row, each 4 consecutive pixels are packed into 5 bytes (40 bits).
+     * Each one of the first 4 bytes contains the top 8 bits of each pixel, The
+     * fifth byte contains the 2 least significant bits of the 4 pixels, the
+     * exact layout data for each 4 consecutive pixels is illustrated below
+     * ({@code Pi[j]} stands for the jth bit of the ith pixel):
      * </p>
      * <table>
      * <thead>
@@ -327,23 +327,26 @@
      * </ul>
      * </p>
      *
-     * <pre>
-     * size = width * height * 10 / 8
-     * </pre>
-     * <p>
-     * Since this is a densely packed format, the pixel and row stride are always
-     * 0. The application must use the pixel data layout defined in above table
-     * to access data.
-     * </p>
+     * <pre>size = row stride * height</pre> where the row stride is in <em>bytes</em>,
+     * not pixels.
      *
      * <p>
+     * Since this is a densely packed format, the pixel stride is always 0. The
+     * application must use the pixel data layout defined in above table to
+     * access each row data. When row stride is equal to {@code width * (10 / 8)}, there
+     * will be no padding bytes at the end of each row, the entire image data is
+     * densely packed. When stride is larger than {@code width * (10 / 8)}, padding
+     * bytes will be present at the end of each row.
+     * </p>
+     * <p>
      * For example, the {@link android.media.Image} object can provide data in
-     * this format from a {@link android.hardware.camera2.CameraDevice} (if supported)
-     * through a {@link android.media.ImageReader} object. The
+     * this format from a {@link android.hardware.camera2.CameraDevice} (if
+     * supported) through a {@link android.media.ImageReader} object. The
      * {@link android.media.Image#getPlanes() Image#getPlanes()} will return a
-     * single plane containing the pixel data. The pixel stride and row stride
-     * are always 0 in {@link android.media.Image.Plane#getPixelStride()} and
-     * {@link android.media.Image.Plane#getRowStride()} respectively.
+     * single plane containing the pixel data. The pixel stride is always 0 in
+     * {@link android.media.Image.Plane#getPixelStride()}, and the
+     * {@link android.media.Image.Plane#getRowStride()} describes the vertical
+     * neighboring pixel distance (in bytes) between adjacent rows.
      * </p>
      *
      * @see android.media.Image
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 90cb217..7b1145c 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -65,7 +65,7 @@
         mColors = colors;
         mPositions = positions;
         mTileMode = tile;
-        native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
+        init(nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt));
     }
 
     /** Create a shader that draws a linear gradient along a line.
@@ -87,7 +87,7 @@
         mColor0 = color0;
         mColor1 = color1;
         mTileMode = tile;
-        native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
+        init(nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt));
     }
 
     /**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 72e39bb..58a1bf2 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -919,7 +919,7 @@
     public Shader setShader(Shader shader) {
         long shaderNative = 0;
         if (shader != null)
-            shaderNative = shader.native_instance;
+            shaderNative = shader.getNativeInstance();
         native_setShader(mNativePaint, shaderNative);
         mShader = shader;
         return shader;
@@ -1260,6 +1260,29 @@
     public native void setTextSkewX(float skewX);
 
     /**
+     * Return the paint's letter-spacing for text. The default value
+     * is 0.
+     *
+     * @return         the paint's letter-spacing for drawing text.
+     * @hide
+     */
+    public float getLetterSpacing() {
+        return native_getLetterSpacing(mNativePaint);
+    }
+
+    /**
+     * Set the paint's letter-spacing for text. The default value
+     * is 0.  The value is in 'EM' units.  Typical values for slight
+     * expansion will be around 0.05.  Negative values tighten text.
+     *
+     * @param letterSpacing set the paint's letter-spacing for drawing text.
+     * @hide
+     */
+    public void setLetterSpacing(float letterSpacing) {
+        native_setLetterSpacing(mNativePaint, letterSpacing);
+    }
+
+    /**
      * Return the distance above (negative) the baseline (ascent) based on the
      * current typeface and text size.
      *
@@ -2232,4 +2255,8 @@
     private static native void native_setShadowLayer(long native_object,
             float radius, float dx, float dy, int color);
     private static native boolean native_hasShadowLayer(long native_object);
+
+    private static native float native_getLetterSpacing(long native_object);
+    private static native void native_setLetterSpacing(long native_object,
+                                                       float letterSpacing);
 }
diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java
index 75c951a..9d015f7 100644
--- a/graphics/java/android/graphics/RadialGradient.java
+++ b/graphics/java/android/graphics/RadialGradient.java
@@ -65,7 +65,7 @@
         mColors = colors;
         mPositions = positions;
         mTileMode = tile;
-        native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
+        init(nativeCreate1(x, y, radius, colors, positions, tile.nativeInt));
     }
 
     /** Create a shader that draws a radial gradient given the center and radius.
@@ -88,7 +88,7 @@
         mColor0 = color0;
         mColor1 = color1;
         mTileMode = tile;
-        native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
+        init(nativeCreate2(x, y, radius, color0, color1, tile.nativeInt));
     }
 
     /**
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 936fe0c..265a564 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -25,10 +25,19 @@
 public class Shader {
     /**
      * This is set by subclasses, but don't make it public.
-     * 
-     * @hide 
      */
-    public long native_instance;
+    private long native_instance;
+
+    private long native_with_local_matrix;
+
+    /**
+     * Initialization step that should be called by subclasses in their
+     * constructors. Calling again may result in memory leaks.
+     * @hide
+     */
+    protected void init(long ni) {
+        native_instance = ni;
+    }
 
     private Matrix mLocalMatrix;
 
@@ -73,21 +82,22 @@
      *
      * Starting with {@link android.os.Build.VERSION_CODES#L}, this does not
      * modify any Paints which use this Shader. In order to modify the Paint,
-     * you need to call {@link Paint#setShader} again.
+     * you need to call {@link Paint#setShader} again. Further, any {@link ComposeShader}s
+     * created with this Shader will be unaffected.
      *
      * @param localM The shader's new local matrix, or null to specify identity
      */
     public void setLocalMatrix(Matrix localM) {
         mLocalMatrix = localM;
-        native_instance = nativeSetLocalMatrix(native_instance,
-                localM == null ? 0 : localM.native_instance);
+        native_with_local_matrix = nativeSetLocalMatrix(native_instance,
+                native_with_local_matrix, localM == null ? 0 : localM.native_instance);
     }
 
     protected void finalize() throws Throwable {
         try {
             super.finalize();
         } finally {
-            nativeDestructor(native_instance);
+            nativeDestructor(native_instance, native_with_local_matrix);
         }
     }
 
@@ -113,7 +123,14 @@
         }
     }
 
-    private static native void nativeDestructor(long native_shader);
+    /* package */ long getNativeInstance() {
+        if (native_with_local_matrix != 0) {
+            return native_with_local_matrix;
+        }
+        return native_instance;
+    }
+
+    private static native void nativeDestructor(long native_shader, long native_with_local_matrix);
     private static native long nativeSetLocalMatrix(long native_shader,
-            long matrix_instance);
+            long native_with_local_matrix, long matrix_instance);
 }
diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java
index 18a748f..008891d 100644
--- a/graphics/java/android/graphics/SweepGradient.java
+++ b/graphics/java/android/graphics/SweepGradient.java
@@ -62,7 +62,7 @@
         mCy = cy;
         mColors = colors;
         mPositions = positions;
-        native_instance = nativeCreate1(cx, cy, colors, positions);
+        init(nativeCreate1(cx, cy, colors, positions));
     }
 
     /**
@@ -79,7 +79,7 @@
         mCy = cy;
         mColor0 = color0;
         mColor1 = color1;
-        native_instance = nativeCreate2(cx, cy, color0, color1);
+        init(nativeCreate2(cx, cy, color0, color1));
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 11c2571..54683aa 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -49,13 +49,11 @@
  * </p>
  * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
  * <pre>
- * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
- *     &lt;size
- *         android:height=&quot;64dp&quot;
- *         android:width=&quot;64dp&quot; /&gt;
- *     &lt;viewport
- *         android:viewportHeight=&quot;600&quot;
- *         android:viewportWidth=&quot;600&quot; /&gt;
+ * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+ *     android:height=&quot;64dp&quot;
+ *     android:width=&quot;64dp&quot;
+ *     android:viewportHeight=&quot;600&quot;
+ *     android:viewportWidth=&quot;600&quot; &gt;
  *     &lt;group
  *         android:name=&quot;rotationGroup&quot;
  *         android:pivotX=&quot;300.0&quot;
@@ -63,7 +61,7 @@
  *         android:rotation=&quot;45.0&quot; &gt;
  *         &lt;path
  *             android:name=&quot;v&quot;
- *             android:fill=&quot;#000000&quot;
+ *             android:fillColor=&quot;#000000&quot;
  *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
  *     &lt;/group&gt;
  * &lt;/vector&gt;
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 2d49365..6f21f2e 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -28,7 +28,6 @@
 import android.util.MathUtils;
 import android.view.HardwareCanvas;
 import android.view.RenderNodeAnimator;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.LinearInterpolator;
 
 import java.util.ArrayList;
@@ -44,16 +43,14 @@
     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 float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
-    private static final float WAVE_OUTER_OPACITY_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 long RIPPLE_ENTER_DELAY = 80;
 
     // Hardware animators.
-    private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
-    private final ArrayList<RenderNodeAnimator> mPendingAnimations = new ArrayList<>();
+    private final ArrayList<RenderNodeAnimator> mRunningAnimations =
+            new ArrayList<RenderNodeAnimator>();
+    private final ArrayList<RenderNodeAnimator> mPendingAnimations =
+            new ArrayList<RenderNodeAnimator>();
 
     private final RippleDrawable mOwner;
 
@@ -79,20 +76,17 @@
     private CanvasProperty<Float> mPropRadius;
     private CanvasProperty<Float> mPropX;
     private CanvasProperty<Float> mPropY;
-    private CanvasProperty<Paint> mPropOuterPaint;
-    private CanvasProperty<Float> mPropOuterRadius;
-    private CanvasProperty<Float> mPropOuterX;
-    private CanvasProperty<Float> mPropOuterY;
 
     // Software animators.
     private ObjectAnimator mAnimRadius;
     private ObjectAnimator mAnimOpacity;
-    private ObjectAnimator mAnimOuterOpacity;
     private ObjectAnimator mAnimX;
     private ObjectAnimator mAnimY;
 
+    // Temporary paint used for creating canvas properties.
+    private Paint mTempPaint;
+
     // Software rendering properties.
-    private float mOuterOpacity = 0;
     private float mOpacity = 1;
     private float mOuterX;
     private float mOuterY;
@@ -177,38 +171,35 @@
         return mOpacity;
     }
 
-    public void setOuterOpacity(float a) {
-        mOuterOpacity = a;
-        invalidateSelf();
-    }
-
-    public float getOuterOpacity() {
-        return mOuterOpacity;
-    }
-
+    @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;
     }
@@ -238,7 +229,7 @@
         // If we have any pending hardware animations, cancel any running
         // animations and start those now.
         final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
-        final int N = pendingAnimations == null ? 0 : pendingAnimations.size();
+        final int N = pendingAnimations.size();
         if (N > 0) {
             cancelHardwareAnimations();
 
@@ -251,7 +242,6 @@
             pendingAnimations.clear();
         }
 
-        c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
         c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
 
         return true;
@@ -262,15 +252,6 @@
 
         // Cache the paint alpha so we can restore it later.
         final int paintAlpha = p.getAlpha();
-
-        final int outerAlpha = (int) (paintAlpha * mOuterOpacity + 0.5f);
-        if (outerAlpha > 0 && mOuterRadius > 0) {
-            p.setAlpha(outerAlpha);
-            p.setStyle(Style.FILL);
-            c.drawCircle(mOuterX, mOuterY, mOuterRadius, p);
-            hasContent = true;
-        }
-
         final int alpha = (int) (paintAlpha * mOpacity + 0.5f);
         final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
         if (alpha > 0 && radius > 0) {
@@ -316,7 +297,6 @@
     public void enter() {
         final int radiusDuration = (int)
                 (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
-        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN);
 
         final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
         radius.setAutoCancel(true);
@@ -336,13 +316,7 @@
         cY.setInterpolator(LINEAR_INTERPOLATOR);
         cY.setStartDelay(RIPPLE_ENTER_DELAY);
 
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
-        outer.setAutoCancel(true);
-        outer.setDuration(outerDuration);
-        outer.setInterpolator(LINEAR_INTERPOLATOR);
-
         mAnimRadius = radius;
-        mAnimOuterOpacity = outer;
         mAnimX = cX;
         mAnimY = cY;
 
@@ -350,7 +324,6 @@
         // that anything interesting is happening until the user lifts their
         // finger.
         radius.start();
-        outer.start();
         cX.start();
         cY.start();
     }
@@ -372,51 +345,23 @@
                 + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
         final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
 
-        // Scale the outer max opacity and opacity velocity based
-        // on the size of the outer radius
-
-        float outerSizeInfluence = MathUtils.constrain(
-                (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
-                / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
-        float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN,
-                WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence);
-
-        // 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 outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
-                / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
-        final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
-                * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
-
         if (mCanUseHardware) {
-            exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+            exitHardware(radiusDuration, opacityDuration);
         } else {
-            exitSoftware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+            exitSoftware(radiusDuration, opacityDuration);
         }
     }
 
-    private void exitHardware(int radiusDuration, int opacityDuration, int outerInflection,
-            int inflectionOpacity) {
+    private void exitHardware(int radiusDuration, int opacityDuration) {
         mPendingAnimations.clear();
 
         final float startX = MathUtils.lerp(
                 mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
         final float startY = MathUtils.lerp(
                 mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
-        final Paint outerPaint = new Paint();
-        outerPaint.setAntiAlias(true);
-        outerPaint.setColor(mColor);
-        outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f));
-        outerPaint.setStyle(Style.FILL);
-        mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
-        mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
-        mPropOuterX = CanvasProperty.createFloat(mOuterX);
-        mPropOuterY = CanvasProperty.createFloat(mOuterY);
 
         final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
-        final Paint paint = new Paint();
+        final Paint paint = getTempPaint();
         paint.setAntiAlias(true);
         paint.setColor(mColor);
         paint.setAlpha((int) (255 * mOpacity + 0.5f));
@@ -442,41 +387,10 @@
                 RenderNodeAnimator.PAINT_ALPHA, 0);
         opacityAnim.setDuration(opacityDuration);
         opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-        final RenderNodeAnimator outerOpacityAnim;
-        if (outerInflection > 0) {
-            // Outer opacity continues to increase for a bit.
-            outerOpacityAnim = new RenderNodeAnimator(
-                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
-            outerOpacityAnim.setDuration(outerInflection);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-            // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - outerInflection;
-            if (outerDuration > 0) {
-                final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator(
-                        mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
-                outerFadeOutAnim.setDuration(outerDuration);
-                outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
-                outerFadeOutAnim.setStartDelay(outerInflection);
-                outerFadeOutAnim.setStartValue(inflectionOpacity);
-                outerFadeOutAnim.addListener(mAnimationListener);
-
-                mPendingAnimations.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);
-        }
+        opacityAnim.addListener(mAnimationListener);
 
         mPendingAnimations.add(radiusAnim);
         mPendingAnimations.add(opacityAnim);
-        mPendingAnimations.add(outerOpacityAnim);
         mPendingAnimations.add(xAnim);
         mPendingAnimations.add(yAnim);
 
@@ -485,8 +399,14 @@
         invalidateSelf();
     }
 
-    private void exitSoftware(int radiusDuration, int opacityDuration, int outerInflection,
-            int inflectionOpacity) {
+    private Paint getTempPaint() {
+        if (mTempPaint == null) {
+            mTempPaint = new Paint();
+        }
+        return mTempPaint;
+    }
+
+    private void exitSoftware(int radiusDuration, int opacityDuration) {
         final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
         radiusAnim.setAutoCancel(true);
         radiusAnim.setDuration(radiusDuration);
@@ -506,58 +426,15 @@
         opacityAnim.setAutoCancel(true);
         opacityAnim.setDuration(opacityDuration);
         opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-        final ObjectAnimator outerOpacityAnim;
-        if (outerInflection > 0) {
-            // Outer opacity continues to increase for a bit.
-            outerOpacityAnim = ObjectAnimator.ofFloat(this,
-                    "outerOpacity", inflectionOpacity / 255.0f);
-            outerOpacityAnim.setAutoCancel(true);
-            outerOpacityAnim.setDuration(outerInflection);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-            // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - outerInflection;
-            if (outerDuration > 0) {
-                outerOpacityAnim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        final ObjectAnimator outerFadeOutAnim = ObjectAnimator.ofFloat(Ripple.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);
-        }
+        opacityAnim.addListener(mAnimationListener);
 
         mAnimRadius = radiusAnim;
         mAnimOpacity = opacityAnim;
-        mAnimOuterOpacity = outerOpacityAnim;
-        mAnimX = opacityAnim;
-        mAnimY = opacityAnim;
+        mAnimX = xAnim;
+        mAnimY = yAnim;
 
         radiusAnim.start();
         opacityAnim.start();
-        outerOpacityAnim.start();
         xAnim.start();
         yAnim.start();
     }
@@ -579,10 +456,6 @@
             mAnimOpacity.cancel();
         }
 
-        if (mAnimOuterOpacity != null) {
-            mAnimOuterOpacity.cancel();
-        }
-
         if (mAnimX != null) {
             mAnimX.cancel();
         }
@@ -597,7 +470,7 @@
      */
     private void cancelHardwareAnimations() {
         final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
-        final int N = runningAnimations == null ? 0 : runningAnimations.size();
+        final int N = runningAnimations.size();
         for (int i = 0; i < N; i++) {
             runningAnimations.get(i).cancel();
         }
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
new file mode 100644
index 0000000..d404ccd
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -0,0 +1,535 @@
+/*
+ * 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.Paint.Style;
+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 RippleBackground {
+    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_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
+    private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
+    private static final float WAVE_OUTER_OPACITY_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 long RIPPLE_ENTER_DELAY = 80;
+
+    // Hardware animators.
+    private final ArrayList<RenderNodeAnimator> mRunningAnimations =
+            new ArrayList<RenderNodeAnimator>();
+    private final ArrayList<RenderNodeAnimator> mPendingAnimations =
+            new ArrayList<RenderNodeAnimator>();
+
+    private final RippleDrawable mOwner;
+
+    /** Bounds used for computing max radius. */
+    private final Rect mBounds;
+
+    /** Full-opacity 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 float mStartingX;
+    private float mStartingY;
+    private float mClampedStartingX;
+    private float mClampedStartingY;
+
+    // Hardware rendering properties.
+    private CanvasProperty<Paint> mPropOuterPaint;
+    private CanvasProperty<Float> mPropOuterRadius;
+    private CanvasProperty<Float> mPropOuterX;
+    private CanvasProperty<Float> mPropOuterY;
+
+    // Software animators.
+    private ObjectAnimator mAnimOuterOpacity;
+    private ObjectAnimator mAnimX;
+    private ObjectAnimator mAnimY;
+
+    // Temporary paint used for creating canvas properties.
+    private Paint mTempPaint;
+
+    // Software rendering properties.
+    private float mOuterOpacity = 0;
+    private float mOuterX;
+    private float mOuterY;
+
+    // Values used to tween between the start and end positions.
+    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;
+
+    /**
+     * Creates a new ripple.
+     */
+    public RippleBackground(RippleDrawable owner, Rect bounds, float startingX, float startingY) {
+        mOwner = owner;
+        mBounds = bounds;
+
+        mStartingX = startingX;
+        mStartingY = startingY;
+    }
+
+    public void setup(int maxRadius, int color, float density) {
+        mColor = color | 0xFF000000;
+
+        if (maxRadius != RippleDrawable.RADIUS_AUTO) {
+            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();
+    }
+
+    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();
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public void setOuterOpacity(float a) {
+        mOuterOpacity = a;
+        invalidateSelf();
+    }
+
+    @SuppressWarnings("unused")
+    public float getOuterOpacity() {
+        return mOuterOpacity;
+    }
+
+    @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();
+        }
+        mCanUseHardware = canUseHardware;
+
+        final boolean hasContent;
+        if (canUseHardware && mHardwareAnimating) {
+            hasContent = drawHardware((HardwareCanvas) c);
+        } else {
+            hasContent = drawSoftware(c, p);
+        }
+
+        return hasContent;
+    }
+
+    private boolean drawHardware(HardwareCanvas c) {
+        // If we have any pending hardware animations, cancel any running
+        // animations and start those now.
+        final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
+        final int N = pendingAnimations.size();
+        if (N > 0) {
+            cancelHardwareAnimations();
+
+            for (int i = 0; i < N; i++) {
+                pendingAnimations.get(i).setTarget(c);
+                pendingAnimations.get(i).start();
+            }
+
+            mRunningAnimations.addAll(pendingAnimations);
+            pendingAnimations.clear();
+        }
+
+        c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
+
+        return true;
+    }
+
+    private boolean drawSoftware(Canvas c, Paint p) {
+        boolean hasContent = false;
+
+        // Cache the paint alpha so we can restore it later.
+        final int paintAlpha = p.getAlpha();
+
+        final int outerAlpha = (int) (paintAlpha * mOuterOpacity + 0.5f);
+        if (outerAlpha > 0 && mOuterRadius > 0) {
+            p.setAlpha(outerAlpha);
+            p.setStyle(Style.FILL);
+            c.drawCircle(mOuterX, mOuterY, mOuterRadius, p);
+            hasContent = true;
+        }
+
+        p.setAlpha(paintAlpha);
+
+        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;
+        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() {
+        final int radiusDuration = (int)
+                (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
+        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN);
+
+        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);
+
+        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+        outer.setAutoCancel(true);
+        outer.setDuration(outerDuration);
+        outer.setInterpolator(LINEAR_INTERPOLATOR);
+
+        mAnimOuterOpacity = outer;
+        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.
+        outer.start();
+        cX.start();
+        cY.start();
+    }
+
+    /**
+     * Starts the exit animation.
+     */
+    public void exit() {
+        cancelSoftwareAnimations();
+
+        // 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_VELOCITY_MIN,
+                WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence);
+
+        // 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 outerInflection = Math.max(0, (int) (1000 * (1 - mOuterOpacity)
+                / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
+        final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
+                * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
+
+        if (mCanUseHardware) {
+            exitHardware(opacityDuration, outerInflection, inflectionOpacity);
+        } else {
+            exitSoftware(opacityDuration, outerInflection, inflectionOpacity);
+        }
+    }
+
+    private void exitHardware(int opacityDuration, int outerInflection, int inflectionOpacity) {
+        mPendingAnimations.clear();
+
+        // TODO: Adjust background by starting position.
+        final float startX = MathUtils.lerp(
+                mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
+        final float startY = MathUtils.lerp(
+                mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
+
+        final Paint outerPaint = getTempPaint();
+        outerPaint.setAntiAlias(true);
+        outerPaint.setColor(mColor);
+        outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f));
+        outerPaint.setStyle(Style.FILL);
+        mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
+        mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
+        mPropOuterX = CanvasProperty.createFloat(mOuterX);
+        mPropOuterY = CanvasProperty.createFloat(mOuterY);
+
+        final RenderNodeAnimator outerOpacityAnim;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacityAnim = new RenderNodeAnimator(
+                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
+            outerOpacityAnim.setDuration(outerInflection);
+            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            if (outerDuration > 0) {
+                final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator(
+                        mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+                outerFadeOutAnim.setDuration(outerDuration);
+                outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
+                outerFadeOutAnim.setStartDelay(outerInflection);
+                outerFadeOutAnim.setStartValue(inflectionOpacity);
+                outerFadeOutAnim.addListener(mAnimationListener);
+
+                mPendingAnimations.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);
+        }
+
+        mPendingAnimations.add(outerOpacityAnim);
+
+        mHardwareAnimating = true;
+
+        invalidateSelf();
+    }
+
+    private Paint getTempPaint() {
+        if (mTempPaint == null) {
+            mTempPaint = new Paint();
+        }
+        return mTempPaint;
+    }
+
+    private void exitSoftware(int opacityDuration, int outerInflection, int inflectionOpacity) {
+        final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1);
+        xAnim.setAutoCancel(true);
+        xAnim.setDuration(opacityDuration);
+        xAnim.setInterpolator(DECEL_INTERPOLATOR);
+
+        final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1);
+        yAnim.setAutoCancel(true);
+        yAnim.setDuration(opacityDuration);
+        yAnim.setInterpolator(DECEL_INTERPOLATOR);
+
+        final ObjectAnimator outerOpacityAnim;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacityAnim = ObjectAnimator.ofFloat(this,
+                    "outerOpacity", inflectionOpacity / 255.0f);
+            outerOpacityAnim.setAutoCancel(true);
+            outerOpacityAnim.setDuration(outerInflection);
+            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            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;
+        mAnimX = xAnim;
+        mAnimY = yAnim;
+
+        outerOpacityAnim.start();
+        xAnim.start();
+        yAnim.start();
+    }
+
+    /**
+     * Cancel all animations.
+     */
+    public void cancel() {
+        cancelSoftwareAnimations();
+        cancelHardwareAnimations();
+    }
+
+    private void cancelSoftwareAnimations() {
+        if (mAnimOuterOpacity != null) {
+            mAnimOuterOpacity.cancel();
+        }
+
+        if (mAnimX != null) {
+            mAnimX.cancel();
+        }
+
+        if (mAnimY != null) {
+            mAnimY.cancel();
+        }
+    }
+
+    /**
+     * Cancels any running hardware animations.
+     */
+    private void cancelHardwareAnimations() {
+        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+        final int N = runningAnimations.size();
+        for (int i = 0; i < N; i++) {
+            runningAnimations.get(i).cancel();
+        }
+
+        runningAnimations.clear();
+    }
+
+    private void removeSelf() {
+        // The owner will invalidate itself.
+        mOwner.removeBackground(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/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 4a1d640..0c9c558 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -120,8 +120,22 @@
     /** The masking layer, e.g. the layer with id R.id.mask. */
     private Drawable mMask;
 
-    /** The current hotspot. May be actively animating or pending entry. */
-    private Ripple mHotspot;
+    /** The current background. May be actively animating or pending entry. */
+    private RippleBackground mBackground;
+
+    /** Whether we expect to draw a background when visible. */
+    private boolean mBackgroundActive;
+
+    /** The current ripple. May be actively animating or pending entry. */
+    private Ripple mRipple;
+
+    /** Whether we expect to draw a ripple when visible. */
+    private boolean mRippleActive;
+
+    // Hotspot coordinates that are awaiting activation.
+    private float mPendingX;
+    private float mPendingY;
+    private boolean mHasPending;
 
     /**
      * Lazily-created array of actively animating ripples. Inactive ripples are
@@ -142,9 +156,6 @@
     /** Whether bounds are being overridden. */
     private boolean mOverrideBounds;
 
-    /** Whether the hotspot is currently active (e.g. focused or pressed). */
-    private boolean mActive;
-
     /**
      * Constructor used for drawable inflation.
      */
@@ -178,6 +189,7 @@
 
         setColor(color);
         ensurePadding();
+        initializeFromState();
     }
 
     @Override
@@ -204,20 +216,26 @@
     protected boolean onStateChange(int[] stateSet) {
         super.onStateChange(stateSet);
 
-        // TODO: This would make more sense in a StateListDrawable.
-        boolean active = false;
         boolean enabled = false;
+        boolean pressed = false;
+        boolean focused = false;
+
         final int N = stateSet.length;
         for (int i = 0; i < N; i++) {
             if (stateSet[i] == R.attr.state_enabled) {
                 enabled = true;
             }
             if (stateSet[i] == R.attr.state_focused
-                    || stateSet[i] == R.attr.state_pressed) {
-                active = true;
+                    || stateSet[i] == R.attr.state_selected) {
+                focused = true;
+            }
+            if (stateSet[i] == R.attr.state_pressed) {
+                pressed = true;
             }
         }
-        setActive(active && enabled);
+
+        setRippleActive(enabled && pressed);
+        setBackgroundActive(focused || (enabled && pressed));
 
         // Update the paint color. Only applicable when animated in software.
         if (mRipplePaint != null && mState.mColor != null) {
@@ -234,14 +252,24 @@
         return false;
     }
 
-    private void setActive(boolean active) {
-        if (mActive != active) {
-            mActive = active;
-
+    private void setRippleActive(boolean active) {
+        if (mRippleActive != active) {
+            mRippleActive = active;
             if (active) {
-                activateHotspot();
+                activateRipple();
             } else {
-                removeHotspot();
+                removeRipple();
+            }
+        }
+    }
+
+    private void setBackgroundActive(boolean active) {
+        if (mBackgroundActive != active) {
+            mBackgroundActive = active;
+            if (active) {
+                activateBackground();
+            } else {
+                removeBackground();
             }
         }
     }
@@ -260,11 +288,23 @@
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
+        final boolean changed = super.setVisible(visible, restart);
+
         if (!visible) {
             clearHotspots();
+        } else if (changed) {
+            // If we just became visible, ensure the background and ripple
+            // visibilities are consistent with their internal states.
+            if (mRippleActive) {
+                activateRipple();
+            }
+
+            if (mBackgroundActive) {
+                activateBackground();
+            }
         }
 
-        return super.setVisible(visible, restart);
+        return changed;
     }
 
     /**
@@ -398,55 +438,101 @@
 
     @Override
     public void setHotspot(float x, float y) {
-        if (mHotspot == null) {
-            mHotspot = new Ripple(this, mHotspotBounds, x, y);
+        if (mRipple == null || mBackground == null) {
+            mPendingX = x;
+            mPendingY = y;
+            mHasPending = true;
+        }
 
-            if (mActive) {
-                activateHotspot();
-            }
-        } else {
-            mHotspot.move(x, y);
+        if (mRipple != null) {
+            mRipple.move(x, y);
+        }
+
+        if (mBackground != null) {
+            mBackground.move(x, y);
         }
     }
 
     /**
      * Creates an active hotspot at the specified location.
      */
-    private void activateHotspot() {
-        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
-            // This should never happen unless the user is tapping like a maniac
-            // or there is a bug that's preventing ripples from being removed.
-            Log.d(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
-            return;
-        }
-
-        if (mHotspot == null) {
-            final float x = mHotspotBounds.exactCenterX();
-            final float y = mHotspotBounds.exactCenterY();
-            mHotspot = new Ripple(this, mHotspotBounds, x, y);
+    private void activateBackground() {
+        if (mBackground == null) {
+            final float x;
+            final float y;
+            if (mHasPending) {
+                mHasPending = false;
+                x = mPendingX;
+                y = mPendingY;
+            } else {
+                x = mHotspotBounds.exactCenterX();
+                y = mHotspotBounds.exactCenterY();
+            }
+            mBackground = new RippleBackground(this, mHotspotBounds, x, y);
         }
 
         final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
-        mHotspot.setup(mState.mMaxRadius, color, mDensity);
-        mHotspot.enter();
+        mBackground.setup(mState.mMaxRadius, color, mDensity);
+        mBackground.enter();
+    }
+
+    private void removeBackground() {
+        if (mBackground != null) {
+            // Don't null out the background, we need it to draw!
+            mBackground.exit();
+        }
+    }
+
+    /**
+     * Creates an active hotspot at the specified location.
+     */
+    private void activateRipple() {
+        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
+            // This should never happen unless the user is tapping like a maniac
+            // or there is a bug that's preventing ripples from being removed.
+            return;
+        }
+
+        if (mRipple == null) {
+            final float x;
+            final float y;
+            if (mHasPending) {
+                mHasPending = false;
+                x = mPendingX;
+                y = mPendingY;
+            } else {
+                x = mHotspotBounds.exactCenterX();
+                y = mHotspotBounds.exactCenterY();
+            }
+            mRipple = new Ripple(this, mHotspotBounds, x, y);
+        }
+
+        final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
+        mRipple.setup(mState.mMaxRadius, color, mDensity);
+        mRipple.enter();
 
         if (mAnimatingRipples == null) {
             mAnimatingRipples = new Ripple[MAX_RIPPLES];
         }
-        mAnimatingRipples[mAnimatingRipplesCount++] = mHotspot;
+        mAnimatingRipples[mAnimatingRipplesCount++] = mRipple;
     }
 
-    private void removeHotspot() {
-        if (mHotspot != null) {
-            mHotspot.exit();
-            mHotspot = null;
+    private void removeRipple() {
+        if (mRipple != null) {
+            mRipple.exit();
+            mRipple = null;
         }
     }
 
     private void clearHotspots() {
-        if (mHotspot != null) {
-            mHotspot.cancel();
-            mHotspot = null;
+        if (mRipple != null) {
+            mRipple.cancel();
+            mRipple = null;
+        }
+
+        if (mBackground != null) {
+            mBackground.cancel();
+            mBackground = null;
         }
 
         final int count = mAnimatingRipplesCount;
@@ -486,6 +572,10 @@
         for (int i = 0; i < count; i++) {
             ripples[i].onHotspotBoundsChanged();
         }
+
+        if (mBackground != null) {
+            mBackground.onHotspotBoundsChanged();
+        }
     }
 
     /**
@@ -524,18 +614,28 @@
         // Next, try to draw the ripples (into a layer if necessary). If we need
         // to mask against the underlying content, set the xfermode to SRC_ATOP.
         final PorterDuffXfermode xfermode = (hasMask || !drawNonMaskContent) ? SRC_OVER : SRC_ATOP;
-        final int rippleLayer = drawRippleLayer(canvas, bounds, xfermode);
+
+        // If we have a background and a non-opaque mask, draw the masking layer.
+        final int backgroundLayer = drawBackgroundLayer(canvas, bounds, xfermode);
+        if (backgroundLayer >= 0) {
+            if (drawMask) {
+                drawMaskingLayer(canvas, bounds, DST_IN);
+            }
+            canvas.restoreToCount(backgroundLayer);
+        }
 
         // If we have ripples and a non-opaque mask, draw the masking layer.
-        if (rippleLayer >= 0 && drawMask) {
-            drawMaskingLayer(canvas, bounds, DST_IN);
+        final int rippleLayer = drawRippleLayer(canvas, bounds, xfermode);
+        if (rippleLayer >= 0) {
+            if (drawMask) {
+                drawMaskingLayer(canvas, bounds, DST_IN);
+            }
+            canvas.restoreToCount(rippleLayer);
         }
 
         // Composite the layers if needed.
         if (contentLayer >= 0) {
             canvas.restoreToCount(contentLayer);
-        } else if (rippleLayer >= 0) {
-            canvas.restoreToCount(rippleLayer);
         }
     }
 
@@ -550,15 +650,20 @@
         final int count = mAnimatingRipplesCount;
         final int index = getRippleIndex(ripple);
         if (index >= 0) {
-            for (int i = index + 1; i < count; i++) {
-                ripples[i - 1] = ripples[i];
-            }
+            System.arraycopy(ripples, index + 1, ripples, index + 1 - 1, count - (index + 1));
             ripples[count - 1] = null;
             mAnimatingRipplesCount--;
             invalidateSelf();
         }
     }
 
+    void removeBackground(RippleBackground background) {
+        if (mBackground == background) {
+            mBackground = null;
+            invalidateSelf();
+        }
+    }
+
     private int getRippleIndex(Ripple ripple) {
         final Ripple[] ripples = mAnimatingRipples;
         final int count = mAnimatingRipplesCount;
@@ -577,7 +682,7 @@
         // We don't need a layer if we don't expect to draw any ripples, we have
         // an explicit mask, or if the non-mask content is all opaque.
         boolean needsLayer = false;
-        if (mAnimatingRipplesCount > 0 && mMask == null) {
+        if ((mAnimatingRipplesCount > 0 || mBackground != null) && mMask == null) {
             for (int i = 0; i < count; i++) {
                 if (array[i].mId != R.id.mask
                         && array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
@@ -601,12 +706,62 @@
         return restoreToCount;
     }
 
-    private int drawRippleLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
-        final int count = mAnimatingRipplesCount;
-        if (count == 0) {
-            return -1;
+    private int drawBackgroundLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
+        // Separate the ripple color and alpha channel. The alpha will be
+        // applied when we merge the ripples down to the canvas.
+        final int rippleARGB;
+        if (mState.mColor != null) {
+            rippleARGB = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
+        } else {
+            rippleARGB = Color.TRANSPARENT;
         }
 
+        if (mRipplePaint == null) {
+            mRipplePaint = new Paint();
+            mRipplePaint.setAntiAlias(true);
+        }
+
+        final int rippleAlpha = Color.alpha(rippleARGB);
+        final Paint ripplePaint = mRipplePaint;
+        ripplePaint.setColor(rippleARGB);
+        ripplePaint.setAlpha(0xFF);
+
+        boolean drewRipples = false;
+        int restoreToCount = -1;
+        int restoreTranslate = -1;
+
+        // Draw background.
+        final RippleBackground background = mBackground;
+        if (background != null) {
+            // If we're masking the ripple layer, make sure we have a layer
+            // first. This will merge SRC_OVER (directly) onto the canvas.
+            final Paint maskingPaint = getMaskingPaint(mode);
+            maskingPaint.setAlpha(rippleAlpha);
+            restoreToCount = canvas.saveLayer(bounds.left, bounds.top,
+                    bounds.right, bounds.bottom, maskingPaint);
+
+            restoreTranslate = canvas.save();
+            // Translate the canvas to the current hotspot bounds.
+            canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
+
+            drewRipples = background.draw(canvas, ripplePaint);
+        }
+
+        // Always restore the translation.
+        if (restoreTranslate >= 0) {
+            canvas.restoreToCount(restoreTranslate);
+        }
+
+        // If we created a layer with no content, merge it immediately.
+        if (restoreToCount >= 0 && !drewRipples) {
+            canvas.restoreToCount(restoreToCount);
+            restoreToCount = -1;
+        }
+
+        return restoreToCount;
+    }
+
+    private int drawRippleLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
         // Separate the ripple color and alpha channel. The alpha will be
         // applied when we merge the ripples down to the canvas.
         final int rippleARGB;
@@ -631,6 +786,7 @@
         int restoreTranslate = -1;
 
         // Draw ripples and update the animating ripples array.
+        final int count = mAnimatingRipplesCount;
         final Ripple[] ripples = mAnimatingRipples;
         for (int i = 0; i < count; i++) {
             final Ripple ripple = ripples[i];
@@ -705,6 +861,13 @@
                 drawingBounds.union(rippleBounds);
             }
 
+            final RippleBackground background = mBackground;
+            if (background != null) {
+                background.getBounds(rippleBounds);
+                rippleBounds.offset(cX, cY);
+                drawingBounds.union(rippleBounds);
+            }
+
             dirtyBounds.union(drawingBounds);
             dirtyBounds.union(super.getDirtyBounds());
             return dirtyBounds;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 13ef89b..f41b11a 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -54,76 +54,130 @@
  * <p/>
  * The vector drawable has the following elements:
  * <p/>
- * <dl>
  * <dt><code>&lt;vector></code></dt>
- * <dd>Used to defined a vector drawable</dd>
- * <dt><code>&lt;size></code></dt>
- * <dd>Used to defined the intrinsic Width Height size of the drawable using
- * <code>android:width</code> and <code>android:height</code></dd>
- * <dt><code>&lt;viewport></code></dt>
- * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
- * The size is defined using the attributes <code>android:viewportHeight</code>
- * <code>android:viewportWidth</code></dd>
+ * <dl>
+ * <dd>Used to defined a vector drawable
+ * <dl>
+ * <dt><code>android:width</code></dt>
+ * <dd>Used to defined the intrinsic width of the drawable.
+ * This support all the dimension units, normally specified with dp.</dd>
+ * <dt><code>android:height</code></dt>
+ * <dd>Used to defined the intrinsic height the drawable.
+ * This support all the dimension units, normally specified with dp.</dd>
+ * <dt><code>android:viewportWidth</code></dt>
+ * <dd>Used to defined the width of the viewport space. Viewport is basically
+ * the virtual canvas where the paths are drawn on.</dd>
+ * <dt><code>android:viewportHeight</code></dt>
+ * <dd>Used to defined the height of the viewport space. Viewport is basically
+ * the virtual canvas where the paths are drawn on.</dd>
+ * <dt><code>android:tint</code></dt>
+ * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
+ * <dt><code>android:tintMode</code></dt>
+ * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
+ * <dt><code>android:autoMirrored</code></dt>
+ * <dd>Indicates if the drawable needs to be mirrored when its layout direction is
+ * RTL (right-to-left).</dd>
+ * </dl></dd>
+ * </dl>
+ *
+ * <dl>
  * <dt><code>&lt;group></code></dt>
  * <dd>Defines a group of paths or subgroups, plus transformation information.
  * The transformations are defined in the same coordinates as the viewport.
- * And the transformations are applied in the order of scale, rotate then translate. </dd>
- * <dt><code>android:rotation</code>
- * <dd>The degrees of rotation of the group.</dd></dt>
- * <dt><code>android:pivotX</code>
- * <dd>The X coordinate of the pivot for the scale and rotation of the group</dd></dt>
- * <dt><code>android:pivotY</code>
- * <dd>The Y coordinate of the pivot for the scale and rotation of the group</dd></dt>
- * <dt><code>android:scaleX</code>
- * <dd>The amount of scale on the X Coordinate</dd></dt>
- * <dt><code>android:scaleY</code>
- * <dd>The amount of scale on the Y coordinate</dd></dt>
- * <dt><code>android:translateX</code>
- * <dd>The amount of translation on the X coordinate</dd></dt>
- * <dt><code>android:translateY</code>
- * <dd>The amount of translation on the Y coordinate</dd></dt>
+ * And the transformations are applied in the order of scale, rotate then translate.
+ * <dl>
+ * <dt><code>android:rotation</code></dt>
+ * <dd>The degrees of rotation of the group.</dd>
+ * <dt><code>android:pivotX</code></dt>
+ * <dd>The X coordinate of the pivot for the scale and rotation of the group.
+ * This is defined in the viewport space.</dd>
+ * <dt><code>android:pivotY</code></dt>
+ * <dd>The Y coordinate of the pivot for the scale and rotation of the group.
+ * This is defined in the viewport space.</dd>
+ * <dt><code>android:scaleX</code></dt>
+ * <dd>The amount of scale on the X Coordinate.</dd>
+ * <dt><code>android:scaleY</code></dt>
+ * <dd>The amount of scale on the Y coordinate.</dd>
+ * <dt><code>android:translateX</code></dt>
+ * <dd>The amount of translation on the X coordinate.
+ * This is defined in the viewport space.</dd>
+ * <dt><code>android:translateY</code></dt>
+ * <dd>The amount of translation on the Y coordinate.
+ * This is defined in the viewport space.</dd>
+ * </dl></dd>
+ * </dl>
+ *
+ * <dl>
  * <dt><code>&lt;path></code></dt>
  * <dd>Defines paths to be drawn.
  * <dl>
- * <dt><code>android:name</code>
- * <dd>Defines the name of the path.</dd></dt>
- * <dt><code>android:pathData</code>
+ * <dt><code>android:name</code></dt>
+ * <dd>Defines the name of the path.</dd>
+ * <dt><code>android:pathData</code></dt>
  * <dd>Defines path string. This is using exactly same format as "d" attribute
- * in the SVG's path data</dd></dt>
- * <dt><code>android:fill</code>
- * <dd>Defines the color to fill the path (none if not present).</dd></dt>
- * <dt><code>android:stroke</code>
+ * in the SVG's path data. This is defined in the viewport space.</dd>
+ * <dt><code>android:fillColor</code></dt>
+ * <dd>Defines the color to fill the path (none if not present).</dd>
+ * <dt><code>android:strokeColor</code></dt>
  * <dd>Defines the color to draw the path outline (none if not present).</dd>
- * </dt>
- * <dt><code>android:strokeWidth</code>
- * <dd>The width a path stroke</dd></dt>
- * <dt><code>android:strokeOpacity</code>
- * <dd>The opacity of a path stroke</dd></dt>
- * <dt><code>android:fillOpacity</code>
- * <dd>The opacity to fill the path with</dd></dt>
- * <dt><code>android:trimPathStart</code>
- * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
- * <dt><code>android:trimPathEnd</code>
- * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
- * <dt><code>android:trimPathOffset</code>
- * <dd>Shift trim region (allows showed region to include the start and end)
- * from 0 to 1</dd></dt>
- * <dt><code>android:clipToPath</code>
- * <dd>Path will set the clip path</dd></dt>
- * <dt><code>android:strokeLineCap</code>
- * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
- * <dt><code>android:strokeLineJoin</code>
- * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
- * <dt><code>android:strokeMiterLimit</code>
- * <dd>Sets the Miter limit for a stroked path</dd></dt>
+ * <dt><code>android:strokeWidth</code></dt>
+ * <dd>The width a path stroke.</dd>
+ * <dt><code>android:strokeOpacity</code></dt>
+ * <dd>The opacity of a path stroke.</dd>
+ * <dt><code>android:fillOpacity</code></dt>
+ * <dd>The opacity to fill the path with.</dd>
+ * <dt><code>android:trimPathStart</code></dt>
+ * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd>
+ * <dt><code>android:trimPathEnd</code></dt>
+ * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd>
+ * <dt><code>android:trimPathOffset</code></dt>
+ * <dd>Shift trim region (allows showed region to include the start and end), in the range
+ * from 0 to 1.</dd>
+ * <dt><code>android:strokeLineCap</code></dt>
+ * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
+ * <dt><code>android:strokeLineJoin</code></dt>
+ * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
+ * <dt><code>android:strokeMiterLimit</code></dt>
+ * <dd>Sets the Miter limit for a stroked path.</dd>
+ * </dl></dd>
  * </dl>
- * </dd>
+ *
+ * <dl>
+ * <dt><code>&lt;clip-path></code></dt>
+ * <dd>Defines path to be the current clip.
+ * <dl>
+ * <dt><code>android:name</code></dt>
+ * <dd>Defines the name of the clip path.</dd>
+ * <dt><code>android:pathData</code></dt>
+ * <dd>Defines clip path string. This is using exactly same format as "d" attribute
+ * in the SVG's path data.</dd>
+ * </dl></dd>
+ * </dl>
+ * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
+ * <pre>
+ * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+ *     android:height=&quot;64dp&quot;
+ *     android:width=&quot;64dp&quot;
+ *     android:viewportHeight=&quot;600&quot;
+ *     android:viewportWidth=&quot;600&quot; &gt;
+ *     &lt;group
+ *         android:name=&quot;rotationGroup&quot;
+ *         android:pivotX=&quot;300.0&quot;
+ *         android:pivotY=&quot;300.0&quot;
+ *         android:rotation=&quot;45.0&quot; &gt;
+ *         &lt;path
+ *             android:name=&quot;v&quot;
+ *             android:fillColor=&quot;#000000&quot;
+ *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
+ *     &lt;/group&gt;
+ * &lt;/vector&gt;
+ * </pre></li>
  */
+
 public class VectorDrawable extends Drawable {
     private static final String LOGTAG = VectorDrawable.class.getSimpleName();
 
-    private static final String SHAPE_SIZE = "size";
-    private static final String SHAPE_VIEWPORT = "viewport";
+    private static final String SHAPE_CLIP_PATH = "clip-path";
     private static final String SHAPE_GROUP = "group";
     private static final String SHAPE_PATH = "path";
     private static final String SHAPE_VECTOR = "vector";
@@ -188,6 +242,12 @@
     public void draw(Canvas canvas) {
         final int saveCount = canvas.save();
         final Rect bounds = getBounds();
+
+        if (bounds.width() == 0 || bounds.height() == 0) {
+            // too small to draw
+            return;
+        }
+
         final boolean needMirroring = needMirroring();
 
         canvas.translate(bounds.left, bounds.top);
@@ -331,20 +391,24 @@
     @Override
     public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
+        final VectorDrawableState state = mVectorState;
+        final VPathRenderer pathRenderer = new VPathRenderer();
+        state.mVPathRenderer = pathRenderer;
+
+        TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
         updateStateFromTypedArray(a);
         a.recycle();
 
-        final VectorDrawableState state = mVectorState;
-        mVectorState.mCacheDirty = true;
+        state.mCacheDirty = true;
         inflateInternal(res, parser, attrs, theme);
 
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
         state.mVPathRenderer.setColorFilter(mTintFilter);
     }
 
-    private void updateStateFromTypedArray(TypedArray a) {
+    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
         final VectorDrawableState state = mVectorState;
+        final VPathRenderer pathRenderer = state.mVPathRenderer;
 
         // Account for any configuration changes.
         state.mChangingConfigurations |= a.getChangingConfigurations();
@@ -364,16 +428,38 @@
 
         state.mAutoMirrored = a.getBoolean(
                 R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
+
+        pathRenderer.mViewportWidth = a.getFloat(
+                R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
+        pathRenderer.mViewportHeight = a.getFloat(
+                R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+
+        if (pathRenderer.mViewportWidth <= 0) {
+            throw new XmlPullParserException(a.getPositionDescription() +
+                    "<viewport> tag requires viewportWidth > 0");
+        } else if (pathRenderer.mViewportHeight <= 0) {
+            throw new XmlPullParserException(a.getPositionDescription() +
+                    "<viewport> tag requires viewportHeight > 0");
+        }
+
+        pathRenderer.mBaseWidth = a.getDimension(
+                R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
+        pathRenderer.mBaseHeight = a.getDimension(
+                R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
+
+        if (pathRenderer.mBaseWidth <= 0) {
+            throw new XmlPullParserException(a.getPositionDescription() +
+                    "<size> tag requires width > 0");
+        } else if (pathRenderer.mBaseHeight <= 0) {
+            throw new XmlPullParserException(a.getPositionDescription() +
+                    "<size> tag requires height > 0");
+        }
     }
 
     private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
         final VectorDrawableState state = mVectorState;
-        final VPathRenderer pathRenderer = new VPathRenderer();
-        state.mVPathRenderer = pathRenderer;
-
-        boolean noSizeTag = true;
-        boolean noViewportTag = true;
+        final VPathRenderer pathRenderer = state.mVPathRenderer;
         boolean noPathTag = true;
 
         // Use a stack to help to build the group tree.
@@ -388,7 +474,7 @@
                 final VGroup currentGroup = groupStack.peek();
 
                 if (SHAPE_PATH.equals(tagName)) {
-                    final VPath path = new VPath();
+                    final VFullPath path = new VFullPath();
                     path.inflate(res, attrs, theme);
                     currentGroup.mChildren.add(path);
                     if (path.getPathName() != null) {
@@ -396,14 +482,14 @@
                     }
                     noPathTag = false;
                     state.mChangingConfigurations |= path.mChangingConfigurations;
-                } else if (SHAPE_SIZE.equals(tagName)) {
-                    pathRenderer.parseSize(res, attrs);
-                    noSizeTag = false;
-                    state.mChangingConfigurations |= pathRenderer.mChangingConfigurations;
-                } else if (SHAPE_VIEWPORT.equals(tagName)) {
-                    pathRenderer.parseViewport(res, attrs);
-                    noViewportTag = false;
-                    state.mChangingConfigurations |= pathRenderer.mChangingConfigurations;
+                } else if (SHAPE_CLIP_PATH.equals(tagName)) {
+                    final VClipPath path = new VClipPath();
+                    path.inflate(res, attrs, theme);
+                    currentGroup.mChildren.add(path);
+                    if (path.getPathName() != null) {
+                        pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+                    }
+                    state.mChangingConfigurations |= path.mChangingConfigurations;
                 } else if (SHAPE_GROUP.equals(tagName)) {
                     VGroup newChildGroup = new VGroup();
                     newChildGroup.inflate(res, attrs, theme);
@@ -429,26 +515,13 @@
             printGroupTree(pathRenderer.mRootGroup, 0);
         }
 
-        if (noSizeTag || noViewportTag || noPathTag) {
+        if (noPathTag) {
             final StringBuffer tag = new StringBuffer();
 
-            if (noSizeTag) {
-                tag.append(SHAPE_SIZE);
+            if (tag.length() > 0) {
+                tag.append(" or ");
             }
-
-            if (noViewportTag) {
-                if (tag.length() > 0) {
-                    tag.append(" & ");
-                }
-                tag.append(SHAPE_SIZE);
-            }
-
-            if (noPathTag) {
-                if (tag.length() > 0) {
-                    tag.append(" or ");
-                }
-                tag.append(SHAPE_PATH);
-            }
+            tag.append(SHAPE_PATH);
 
             throw new XmlPullParserException("no " + tag + " defined");
         }
@@ -605,10 +678,10 @@
         // Variables below need to be copied (deep copy if applicable) for mutation.
         private int mChangingConfigurations;
         private final VGroup mRootGroup;
-        private float mBaseWidth = 0;
-        private float mBaseHeight = 0;
-        private float mViewportWidth = 0;
-        private float mViewportHeight = 0;
+        float mBaseWidth = 0;
+        float mBaseHeight = 0;
+        float mViewportWidth = 0;
+        float mViewportHeight = 0;
         private int mRootAlpha = 0xFF;
 
         final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
@@ -730,7 +803,8 @@
 
         public void draw(Canvas canvas, int w, int h) {
             // Travese the tree in pre-order to draw.
-            drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, canvas, w, h);
+            drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF,
+                    canvas, w, h);
         }
 
         private void drawPath(VGroup vGroup, VPath vPath, float stackedAlpha,
@@ -740,54 +814,53 @@
             final float minScale = Math.min(scaleX, scaleY);
 
             mFinalPathMatrix.set(vGroup.mStackedMatrix);
-            mFinalPathMatrix.postScale(scaleX, scaleY, mViewportWidth / 2f, mViewportHeight / 2f);
-            mFinalPathMatrix.postTranslate(
-                    w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
+            mFinalPathMatrix.postScale(scaleX, scaleY);
 
             vPath.toPath(mPath);
             final Path path = mPath;
 
-            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
-                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
-                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
-
-                if (mPathMeasure == null) {
-                    mPathMeasure = new PathMeasure();
-                }
-                mPathMeasure.setPath(mPath, false);
-
-                float len = mPathMeasure.getLength();
-                start = start * len;
-                end = end * len;
-                path.reset();
-                if (start > end) {
-                    mPathMeasure.getSegment(start, len, path, true);
-                    mPathMeasure.getSegment(0f, end, path, true);
-                } else {
-                    mPathMeasure.getSegment(start, end, path, true);
-                }
-                path.rLineTo(0, 0); // fix bug in measure
-            }
-
             mRenderPath.reset();
 
-            mRenderPath.addPath(path, mFinalPathMatrix);
-
-            if (vPath.mClip) {
+            if (vPath.isClipPath()) {
+                mRenderPath.addPath(path, mFinalPathMatrix);
                 canvas.clipPath(mRenderPath, Region.Op.REPLACE);
             } else {
-                if (vPath.mFillColor != 0) {
+                VFullPath fullPath = (VFullPath) vPath;
+                if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
+                    float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
+                    float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
+
+                    if (mPathMeasure == null) {
+                        mPathMeasure = new PathMeasure();
+                    }
+                    mPathMeasure.setPath(mPath, false);
+
+                    float len = mPathMeasure.getLength();
+                    start = start * len;
+                    end = end * len;
+                    path.reset();
+                    if (start > end) {
+                        mPathMeasure.getSegment(start, len, path, true);
+                        mPathMeasure.getSegment(0f, end, path, true);
+                    } else {
+                        mPathMeasure.getSegment(start, end, path, true);
+                    }
+                    path.rLineTo(0, 0); // fix bug in measure
+                }
+                mRenderPath.addPath(path, mFinalPathMatrix);
+
+                if (fullPath.mFillColor != 0) {
                     if (mFillPaint == null) {
                         mFillPaint = new Paint();
                         mFillPaint.setColorFilter(mColorFilter);
                         mFillPaint.setStyle(Paint.Style.FILL);
                         mFillPaint.setAntiAlias(true);
                     }
-                    mFillPaint.setColor(applyAlpha(vPath.mFillColor, stackedAlpha));
+                    mFillPaint.setColor(applyAlpha(fullPath.mFillColor, stackedAlpha));
                     canvas.drawPath(mRenderPath, mFillPaint);
                 }
 
-                if (vPath.mStrokeColor != 0) {
+                if (fullPath.mStrokeColor != 0) {
                     if (mStrokePaint == null) {
                         mStrokePaint = new Paint();
                         mStrokePaint.setColorFilter(mColorFilter);
@@ -796,70 +869,25 @@
                     }
 
                     final Paint strokePaint = mStrokePaint;
-                    if (vPath.mStrokeLineJoin != null) {
-                        strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
+                    if (fullPath.mStrokeLineJoin != null) {
+                        strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
                     }
 
-                    if (vPath.mStrokeLineCap != null) {
-                        strokePaint.setStrokeCap(vPath.mStrokeLineCap);
+                    if (fullPath.mStrokeLineCap != null) {
+                        strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
                     }
 
-                    strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * minScale);
+                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit * minScale);
 
-                    strokePaint.setColor(applyAlpha(vPath.mStrokeColor, stackedAlpha));
-                    strokePaint.setStrokeWidth(vPath.mStrokeWidth * minScale);
+                    strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, stackedAlpha));
+                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale);
                     canvas.drawPath(mRenderPath, strokePaint);
                 }
             }
         }
-
-        private void parseViewport(Resources r, AttributeSet attrs)
-                throws XmlPullParserException {
-            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
-
-            // Account for any configuration changes.
-            mChangingConfigurations |= a.getChangingConfigurations();
-
-            mViewportWidth = a.getFloat(
-                    R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth);
-            mViewportHeight = a.getFloat(
-                    R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight);
-
-            if (mViewportWidth <= 0) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        "<viewport> tag requires viewportWidth > 0");
-            } else if (mViewportHeight <= 0) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        "<viewport> tag requires viewportHeight > 0");
-            }
-
-            a.recycle();
-        }
-
-        private void parseSize(Resources r, AttributeSet attrs)
-                throws XmlPullParserException {
-            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
-
-            // Account for any configuration changes.
-            mChangingConfigurations |= a.getChangingConfigurations();
-
-            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth);
-            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight);
-
-            if (mBaseWidth <= 0) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        "<size> tag requires width > 0");
-            } else if (mBaseHeight <= 0) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        "<size> tag requires height > 0");
-            }
-
-            a.recycle();
-        }
-
     }
 
-    static class VGroup {
+    private static class VGroup {
         // mStackedMatrix is only used temporarily when drawing, it combines all
         // the parents' local matrices with the current one.
         private final Matrix mStackedMatrix = new Matrix();
@@ -908,9 +936,15 @@
                 if (copyChild instanceof VGroup) {
                     VGroup copyGroup = (VGroup) copyChild;
                     mChildren.add(new VGroup(copyGroup, targetsMap));
-                } else if (copyChild instanceof VPath) {
-                    VPath copyPath = (VPath) copyChild;
-                    VPath newPath = new VPath(copyPath);
+                } else {
+                    VPath newPath = null;
+                    if (copyChild instanceof VFullPath) {
+                        newPath = new VFullPath((VFullPath) copyChild);
+                    } else if (copyChild instanceof VClipPath) {
+                        newPath = new VClipPath((VClipPath) copyChild);
+                    } else {
+                        throw new IllegalStateException("Unknown object in the tree!");
+                    }
                     mChildren.add(newPath);
                     if (newPath.mPathName != null) {
                         targetsMap.put(newPath.mPathName, newPath);
@@ -922,94 +956,6 @@
         public VGroup() {
         }
 
-        /* Getter and Setter */
-        public float getRotation() {
-            return mRotate;
-        }
-
-        public void setRotation(float rotation) {
-            if (rotation != mRotate) {
-                mRotate = rotation;
-                updateLocalMatrix();
-            }
-        }
-
-        public float getPivotX() {
-            return mPivotX;
-        }
-
-        public void setPivotX(float pivotX) {
-            if (pivotX != mPivotX) {
-                mPivotX = pivotX;
-                updateLocalMatrix();
-            }
-        }
-
-        public float getPivotY() {
-            return mPivotY;
-        }
-
-        public void setPivotY(float pivotY) {
-            if (pivotY != mPivotY) {
-                mPivotY = pivotY;
-                updateLocalMatrix();
-            }
-        }
-
-        public float getScaleX() {
-            return mScaleX;
-        }
-
-        public void setScaleX(float scaleX) {
-            if (scaleX != mScaleX) {
-                mScaleX = scaleX;
-                updateLocalMatrix();
-            }
-        }
-
-        public float getScaleY() {
-            return mScaleY;
-        }
-
-        public void setScaleY(float scaleY) {
-            if (scaleY != mScaleY) {
-                mScaleY = scaleY;
-                updateLocalMatrix();
-            }
-        }
-
-        public float getTranslateX() {
-            return mTranslateX;
-        }
-
-        public void setTranslateX(float translateX) {
-            if (translateX != mTranslateX) {
-                mTranslateX = translateX;
-                updateLocalMatrix();
-            }
-        }
-
-        public float getTranslateY() {
-            return mTranslateY;
-        }
-
-        public void setTranslateY(float translateY) {
-            if (translateY != mTranslateY) {
-                mTranslateY = translateY;
-                updateLocalMatrix();
-            }
-        }
-
-        public float getAlpha() {
-            return mGroupAlpha;
-        }
-
-        public void setAlpha(float groupAlpha) {
-            if (groupAlpha != mGroupAlpha) {
-                mGroupAlpha = groupAlpha;
-            }
-        }
-
         public String getGroupName() {
             return mGroupName;
         }
@@ -1058,7 +1004,8 @@
                 return;
             }
 
-            final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+            final TypedArray a = t.resolveAttributes(mThemeAttrs,
+                    R.styleable.VectorDrawableGroup);
             updateStateFromTypedArray(a);
             a.recycle();
         }
@@ -1072,9 +1019,207 @@
             mLocalMatrix.postRotate(mRotate, 0, 0);
             mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
         }
+
+        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+        @SuppressWarnings("unused")
+        public float getRotation() {
+            return mRotate;
+        }
+
+        @SuppressWarnings("unused")
+        public void setRotation(float rotation) {
+            if (rotation != mRotate) {
+                mRotate = rotation;
+                updateLocalMatrix();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public float getPivotX() {
+            return mPivotX;
+        }
+
+        @SuppressWarnings("unused")
+        public void setPivotX(float pivotX) {
+            if (pivotX != mPivotX) {
+                mPivotX = pivotX;
+                updateLocalMatrix();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public float getPivotY() {
+            return mPivotY;
+        }
+
+        @SuppressWarnings("unused")
+        public void setPivotY(float pivotY) {
+            if (pivotY != mPivotY) {
+                mPivotY = pivotY;
+                updateLocalMatrix();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public float getScaleX() {
+            return mScaleX;
+        }
+
+        @SuppressWarnings("unused")
+        public void setScaleX(float scaleX) {
+            if (scaleX != mScaleX) {
+                mScaleX = scaleX;
+                updateLocalMatrix();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public float getScaleY() {
+            return mScaleY;
+        }
+
+        @SuppressWarnings("unused")
+        public void setScaleY(float scaleY) {
+            if (scaleY != mScaleY) {
+                mScaleY = scaleY;
+                updateLocalMatrix();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public float getTranslateX() {
+            return mTranslateX;
+        }
+
+        @SuppressWarnings("unused")
+        public void setTranslateX(float translateX) {
+            if (translateX != mTranslateX) {
+                mTranslateX = translateX;
+                updateLocalMatrix();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public float getTranslateY() {
+            return mTranslateY;
+        }
+
+        @SuppressWarnings("unused")
+        public void setTranslateY(float translateY) {
+            if (translateY != mTranslateY) {
+                mTranslateY = translateY;
+                updateLocalMatrix();
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public float getAlpha() {
+            return mGroupAlpha;
+        }
+
+        @SuppressWarnings("unused")
+        public void setAlpha(float groupAlpha) {
+            if (groupAlpha != mGroupAlpha) {
+                mGroupAlpha = groupAlpha;
+            }
+        }
     }
 
+    /**
+     * Common Path information for clip path and normal path.
+     */
     private static class VPath {
+        protected PathParser.PathDataNode[] mNodes = null;
+        String mPathName;
+        int mChangingConfigurations;
+
+        public VPath() {
+            // Empty constructor.
+        }
+
+        public VPath(VPath copy) {
+            mPathName = copy.mPathName;
+            mChangingConfigurations = copy.mChangingConfigurations;
+            mNodes = PathParser.deepCopyNodes(copy.mNodes);
+        }
+
+        public void toPath(Path path) {
+            path.reset();
+            if (mNodes != null) {
+                PathParser.PathDataNode.nodesToPath(mNodes, path);
+            }
+        }
+
+        public String getPathName() {
+            return mPathName;
+        }
+
+        public boolean canApplyTheme() {
+            return false;
+        }
+
+        public void applyTheme(Theme t) {
+        }
+
+        public boolean isClipPath() {
+            return false;
+        }
+
+        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+        @SuppressWarnings("unused")
+        public PathParser.PathDataNode[] getPathData() {
+            return mNodes;
+        }
+
+        @SuppressWarnings("unused")
+        public void setPathData(PathParser.PathDataNode[] nodes) {
+            if (!PathParser.canMorph(mNodes, nodes)) {
+                // This should not happen in the middle of animation.
+                mNodes = PathParser.deepCopyNodes(nodes);
+            } else {
+                PathParser.updateNodes(mNodes, nodes);
+            }
+        }
+    }
+
+    /**
+     * Clip path, which only has name and pathData.
+     */
+    private static class VClipPath extends VPath{
+        public VClipPath() {
+            // Empty constructor.
+        }
+
+        public VClipPath(VClipPath copy) {
+            super(copy);
+        }
+
+        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+            final TypedArray a = obtainAttributes(r, theme, attrs,
+                    R.styleable.VectorDrawableClipPath);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+
+        private void updateStateFromTypedArray(TypedArray a) {
+            // Account for any configuration changes.
+            mChangingConfigurations |= a.getChangingConfigurations();
+
+            mPathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+            mNodes = PathParser.createNodesFromPathData(a.getString(
+                    R.styleable.VectorDrawableClipPath_pathData));
+        }
+
+        @Override
+        public boolean isClipPath() {
+            return true;
+        }
+    }
+
+    /**
+     * Normal path, which contains all the fill / paint information.
+     */
+    private static class VFullPath extends VPath {
         /////////////////////////////////////////////////////
         // Variables below need to be copied (deep copy if applicable) for mutation.
         private int[] mThemeAttrs;
@@ -1089,20 +1234,16 @@
         float mTrimPathEnd = 1;
         float mTrimPathOffset = 0;
 
-        boolean mClip = false;
         Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
         Paint.Join mStrokeLineJoin = Paint.Join.MITER;
         float mStrokeMiterlimit = 4;
 
-        private PathParser.PathDataNode[] mNodes = null;
-        String mPathName;
-        private int mChangingConfigurations;
-
-        public VPath() {
+        public VFullPath() {
             // Empty constructor.
         }
 
-        public VPath(VPath copy) {
+        public VFullPath(VFullPath copy) {
+            super(copy);
             mThemeAttrs = copy.mThemeAttrs;
 
             mStrokeColor = copy.mStrokeColor;
@@ -1115,25 +1256,9 @@
             mTrimPathEnd = copy.mTrimPathEnd;
             mTrimPathOffset = copy.mTrimPathOffset;
 
-            mClip = copy.mClip;
             mStrokeLineCap = copy.mStrokeLineCap;
             mStrokeLineJoin = copy.mStrokeLineJoin;
             mStrokeMiterlimit = copy.mStrokeMiterlimit;
-
-            mNodes = PathParser.deepCopyNodes(copy.mNodes);
-            mPathName = copy.mPathName;
-            mChangingConfigurations = copy.mChangingConfigurations;
-        }
-
-        public void toPath(Path path) {
-            path.reset();
-            if (mNodes != null) {
-                PathParser.PathDataNode.nodesToPath(mNodes, path);
-            }
-        }
-
-        public String getPathName() {
-            return mPathName;
         }
 
         private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
@@ -1162,22 +1287,78 @@
             }
         }
 
-        /* Setters and Getters, mostly used by animator from AnimatedVectorDrawable. */
-        @SuppressWarnings("unused")
-        public PathParser.PathDataNode[] getPathData() {
-            return mNodes;
+        @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null;
         }
 
-        @SuppressWarnings("unused")
-        public void setPathData(PathParser.PathDataNode[] nodes) {
-            if (!PathParser.canMorph(mNodes, nodes)) {
-                // This should not happen in the middle of animation.
-                mNodes = PathParser.deepCopyNodes(nodes);
-            } else {
-                PathParser.updateNodes(mNodes, nodes);
+        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+            final TypedArray a = obtainAttributes(r, theme, attrs,
+                    R.styleable.VectorDrawablePath);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+
+        private void updateStateFromTypedArray(TypedArray a) {
+            // Account for any configuration changes.
+            mChangingConfigurations |= a.getChangingConfigurations();
+
+            // Extract the theme attributes, if any.
+            mThemeAttrs = a.extractThemeAttrs();
+
+            mPathName = a.getString(R.styleable.VectorDrawablePath_name);
+            mNodes = PathParser.createNodesFromPathData(a.getString(
+                    R.styleable.VectorDrawablePath_pathData));
+
+            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
+                    mFillColor);
+            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity,
+                    mFillOpacity);
+            mStrokeLineCap = getStrokeLineCap(a.getInt(
+                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
+            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
+                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
+            mStrokeMiterlimit = a.getFloat(
+                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
+            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor,
+                    mStrokeColor);
+            mStrokeOpacity = a.getFloat(R.styleable.VectorDrawablePath_strokeOpacity,
+                    mStrokeOpacity);
+            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
+                    mStrokeWidth);
+            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
+                    mTrimPathEnd);
+            mTrimPathOffset = a.getFloat(
+                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
+            mTrimPathStart = a.getFloat(
+                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+
+            updateColorAlphas();
+        }
+
+        @Override
+        public void applyTheme(Theme t) {
+            if (mThemeAttrs == null) {
+                return;
+            }
+
+            final TypedArray a = t.resolveAttributes(mThemeAttrs,
+                    R.styleable.VectorDrawablePath);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+
+        private void updateColorAlphas() {
+            if (!Float.isNaN(mFillOpacity)) {
+                mFillColor = applyAlpha(mFillColor, mFillOpacity);
+            }
+
+            if (!Float.isNaN(mStrokeOpacity)) {
+                mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity);
             }
         }
 
+        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
         @SuppressWarnings("unused")
         int getStroke() {
             return mStrokeColor;
@@ -1257,69 +1438,5 @@
         void setTrimPathOffset(float trimPathOffset) {
             mTrimPathOffset = trimPathOffset;
         }
-
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null;
-        }
-
-        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
-            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
-            updateStateFromTypedArray(a);
-            a.recycle();
-        }
-
-        private void updateStateFromTypedArray(TypedArray a) {
-            // Account for any configuration changes.
-            mChangingConfigurations |= a.getChangingConfigurations();
-
-            // Extract the theme attributes, if any.
-            mThemeAttrs = a.extractThemeAttrs();
-
-            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
-
-            mPathName = a.getString(R.styleable.VectorDrawablePath_name);
-            mNodes = PathParser.createNodesFromPathData(a.getString(
-                    R.styleable.VectorDrawablePath_pathData));
-
-            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
-            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
-            mStrokeLineCap = getStrokeLineCap(a.getInt(
-                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
-            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
-                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
-            mStrokeMiterlimit = a.getFloat(
-                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
-            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
-            mStrokeOpacity = a.getFloat(
-                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
-            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
-            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
-            mTrimPathOffset = a.getFloat(
-                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
-            mTrimPathStart = a.getFloat(
-                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
-
-            updateColorAlphas();
-        }
-
-        public void applyTheme(Theme t) {
-            if (mThemeAttrs == null) {
-                return;
-            }
-
-            final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
-            updateStateFromTypedArray(a);
-            a.recycle();
-        }
-
-        private void updateColorAlphas() {
-            if (!Float.isNaN(mFillOpacity)) {
-                mFillColor = applyAlpha(mFillColor, mFillOpacity);
-            }
-
-            if (!Float.isNaN(mStrokeOpacity)) {
-                mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity);
-            }
-        }
     }
 }
diff --git a/include/private/graphics/Canvas.h b/include/private/graphics/Canvas.h
new file mode 100644
index 0000000..3cd57f4
--- /dev/null
+++ b/include/private/graphics/Canvas.h
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GRAPHICS_CANVAS_H
+#define ANDROID_GRAPHICS_CANVAS_H
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkMatrix.h"
+
+namespace android {
+
+class Canvas {
+public:
+    virtual ~Canvas() {};
+
+    static Canvas* create_canvas(SkBitmap* bitmap);
+    static Canvas* create_canvas(SkCanvas* skiaCanvas);
+
+    // TODO: enable HWUI to either create similar canvas wrapper or subclass
+    //       directly from Canvas
+    //static Canvas* create_canvas(uirenderer::Renderer* renderer);
+
+    // TODO: this is a temporary affordance until all necessary logic can be
+    //       moved within this interface! Further, the return value should
+    //       NOT be unref'd and is valid until this canvas is destroyed or a
+    //       new bitmap is set.
+    virtual SkCanvas* getSkCanvas() = 0;
+
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0;
+
+    virtual bool isOpaque() = 0;
+    virtual int width() = 0;
+    virtual int height() = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas state operations
+// ----------------------------------------------------------------------------
+    // Save (layer)
+    virtual int getSaveCount() const = 0;
+    virtual int save(SkCanvas::SaveFlags flags) = 0;
+    virtual void restore() = 0;
+    virtual void restoreToCount(int saveCount) = 0;
+
+    virtual int saveLayer(float left, float top, float right, float bottom,
+                const SkPaint* paint, SkCanvas::SaveFlags flags) = 0;
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, SkCanvas::SaveFlags flags) = 0;
+
+    // Matrix
+    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
+    virtual void setMatrix(const SkMatrix& matrix) = 0;
+
+    virtual void concat(const SkMatrix& matrix) = 0;
+    virtual void rotate(float degrees) = 0;
+    virtual void scale(float sx, float sy) = 0;
+    virtual void skew(float sx, float sy) = 0;
+    virtual void translate(float dx, float dy) = 0;
+
+    // clip
+    virtual bool getClipBounds(SkRect* outRect) const = 0;
+    virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
+    virtual bool quickRejectPath(const SkPath& path) const = 0;
+
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
+
+    // filters
+    virtual SkDrawFilter* getDrawFilter() = 0;
+    virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations
+// ----------------------------------------------------------------------------
+    virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
+    virtual void drawPaint(const SkPaint& paint) = 0;
+
+    // Geometry
+    virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
+    virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0;
+    virtual void drawLine(float startX, float startY, float stopX, float stopY,
+                const SkPaint& paint) = 0;
+    virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0;
+    virtual void drawRect(float left, float top, float right, float bottom,
+            const SkPaint& paint) = 0;
+    virtual void drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint& paint) = 0;
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
+    virtual void drawOval(float left, float top, float right, float bottom,
+            const SkPaint& paint) = 0;
+    virtual void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
+    virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
+    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) = 0;
+
+    // Bitmap-based
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
+            const SkPaint* paint) = 0;
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+            const SkPaint* paint) = 0;
+    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint) = 0;
+    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint) = 0;
+
+    // Text
+    virtual void drawText(const uint16_t* text, const float* positions, int count,
+            const SkPaint& paint, float x, float y,
+            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom) = 0;
+    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
+            int posCount, const SkPaint& paint) = 0;
+    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) = 0;
+
+    /*
+     * Specifies if the positions passed to ::drawText are absolute or relative
+     * to the (x,y) value provided.
+     *
+     * If true the (x,y) values are ignored. Otherwise, those (x,y) values need
+     * to be added to each glyph's position to get its absolute position.
+     */
+    virtual bool drawTextAbsolutePos() const = 0;
+};
+
+}; // namespace android
+#endif // ANDROID_GRAPHICS_CANVAS_H
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 937b7c6..181230a 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -48,7 +48,6 @@
         const Vector3* vertices, int vertexCount, const Vector3& centroid3d,
         float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
     const int rays = SHADOW_RAY_COUNT;
-    VertexBuffer::Mode mode = VertexBuffer::kOnePolyRingShadow;
     // Validate the inputs.
     if (vertexCount < 3 || heightFactor <= 0 || rays <= 0
         || geomFactor <= 0) {
@@ -98,9 +97,9 @@
     // calculate the normal N, which should be perpendicular to the edge of the
     // polygon (represented by the neighbor intersection points) .
     // Shadow's vertices will be generated as : P + N * scale.
-    const Vector2 centroid2d = Vector2(centroid3d.x, centroid3d.y);
+    const Vector2 centroid2d = {centroid3d.x, centroid3d.y};
     for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
-        Vector2 normal(1.0f, 0.0f);
+        Vector2 normal = {1.0f, 0.0f};
         calculateNormal(rays, rayIndex, dir.array(), rayDist, normal);
 
         // The vertex should be start from rayDist[i] then scale the
@@ -124,18 +123,23 @@
                 opacity);
     }
 
-    // If caster isn't opaque, we need to to fill the umbra by storing the umbra's
-    // centroid in the innermost ring of vertices.
-    if (!isCasterOpaque) {
-        mode = VertexBuffer::kTwoPolyRingShadow;
+    if (isCasterOpaque) {
+        // skip inner ring, calc bounds over filled portion of buffer
+        shadowVertexBuffer.computeBounds<AlphaVertex>(2 * rays);
+        shadowVertexBuffer.setMode(VertexBuffer::kOnePolyRingShadow);
+    } else {
+        // If caster isn't opaque, we need to to fill the umbra by storing the umbra's
+        // centroid in the innermost ring of vertices.
         float centroidAlpha = 1.0 / (1 + centroid3d.z * heightFactor);
         AlphaVertex centroidXYA;
         AlphaVertex::set(&centroidXYA, centroid2d.x, centroid2d.y, centroidAlpha);
         for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
             shadowVertices[2 * rays + rayIndex] = centroidXYA;
         }
+        // calc bounds over entire buffer
+        shadowVertexBuffer.computeBounds<AlphaVertex>();
+        shadowVertexBuffer.setMode(VertexBuffer::kTwoPolyRingShadow);
     }
-    shadowVertexBuffer.setMode(mode);
 
 #if DEBUG_SHADOW
     for (int i = 0; i < SHADOW_VERTEX_COUNT; i++) {
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 9202e49..bf7828c 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -49,7 +49,7 @@
     LayerRenderer(RenderState& renderState, Layer* layer);
     virtual ~LayerRenderer();
 
-    virtual void onViewportInitialized(int width, int height) { /* do nothing */ }
+    virtual void onViewportInitialized() { /* do nothing */ }
     virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5a96132..41f89c2 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -132,19 +132,21 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
-        : mCaches(Caches::getInstance())
+        : mFrameStarted(false)
+        , mCaches(Caches::getInstance())
         , mExtensions(Extensions::getInstance())
-        , mRenderState(renderState) {
+        , mRenderState(renderState)
+        , mScissorOptimizationDisabled(false)
+        , mCountOverdraw(false)
+        , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
+        , mLightRadius(FLT_MIN)
+        , mAmbientShadowAlpha(0)
+        , mSpotShadowAlpha(0) {
     // *set* draw modifiers to be 0
     memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
     mDrawModifiers.mOverrideLayerAlpha = 1.0f;
 
     memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
-
-    mFrameStarted = false;
-    mCountOverdraw = false;
-
-    mScissorOptimizationDisabled = false;
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -163,6 +165,14 @@
     }
 }
 
+void OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius,
+        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+    mLightCenter = lightCenter;
+    mLightRadius = lightRadius;
+    mAmbientShadowAlpha = ambientShadowAlpha;
+    mSpotShadowAlpha = spotShadowAlpha;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Setup
 ///////////////////////////////////////////////////////////////////////////////
@@ -1924,7 +1934,9 @@
         return deferredList.flush(*this, dirty) | status;
     }
 
-    return DrawGlInfo::kStatusDone;
+    // Even if there is no drawing command(Ex: invisible),
+    // it still needs startFrame to clear buffer and start tiling.
+    return startFrame();
 }
 
 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
@@ -3172,13 +3184,13 @@
     SkPaint paint;
     paint.setAntiAlias(true); // want to use AlphaVertex
 
-    if (ambientShadowVertexBuffer && mCaches.propertyAmbientShadowStrength > 0) {
-        paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
+    if (ambientShadowVertexBuffer && mAmbientShadowAlpha > 0) {
+        paint.setARGB(casterAlpha * mAmbientShadowAlpha, 0, 0, 0);
         drawVertexBuffer(*ambientShadowVertexBuffer, &paint);
     }
 
-    if (spotShadowVertexBuffer && mCaches.propertySpotShadowStrength > 0) {
-        paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0);
+    if (spotShadowVertexBuffer && mSpotShadowAlpha > 0) {
+        paint.setARGB(casterAlpha * mSpotShadowAlpha, 0, 0, 0);
         drawVertexBuffer(*spotShadowVertexBuffer, &paint);
     }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 4e7844b..f698b45 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -124,6 +124,8 @@
     virtual ~OpenGLRenderer();
 
     void initProperties();
+    void initLight(const Vector3& lightCenter, float lightRadius,
+            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
 
     virtual void onViewportInitialized();
     virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
@@ -1010,6 +1012,12 @@
 
     bool mSkipOutlineClip;
 
+    // Lighting + shadows
+    Vector3 mLightCenter;
+    float mLightRadius;
+    uint8_t mAmbientShadowAlpha;
+    uint8_t mSpotShadowAlpha;
+
     friend class Layer;
     friend class TextSetupFunctor;
     friend class DrawBitmapOp;
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 310b107..209341c 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -90,7 +90,7 @@
  *
  * NOTE: assumes angles between normals 90 degrees or less
  */
-inline static vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) {
+inline static Vector2 totalOffsetFromNormals(const Vector2& normalA, const Vector2& normalB) {
     return (normalA + normalB) / (1 + fabs(normalA.dot(normalB)));
 }
 
@@ -129,7 +129,7 @@
     float halfStrokeWidth;
     float maxAlpha;
 
-    inline void scaleOffsetForStrokeWidth(vec2& offset) const {
+    inline void scaleOffsetForStrokeWidth(Vector2& offset) const {
         if (halfStrokeWidth == 0.0f) {
             // hairline - compensate for scale
             offset.x *= 0.5f * inverseScaleX;
@@ -143,9 +143,8 @@
      * NOTE: the input will not always be a normal, especially for sharp edges - it should be the
      * result of totalOffsetFromNormals (see documentation there)
      */
-    inline vec2 deriveAAOffset(const vec2& offset) const {
-        return vec2(offset.x * 0.5f * inverseScaleX,
-            offset.y * 0.5f * inverseScaleY);
+    inline Vector2 deriveAAOffset(const Vector2& offset) const {
+        return (Vector2){offset.x * 0.5f * inverseScaleX, offset.y * 0.5f * inverseScaleY};
     }
 
     /**
@@ -208,16 +207,14 @@
     int currentIndex = 0;
     const Vertex* last = &(perimeter[perimeter.size() - 1]);
     const Vertex* current = &(perimeter[0]);
-    vec2 lastNormal(current->y - last->y,
-            last->x - current->x);
+    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
     lastNormal.normalize();
     for (unsigned int i = 0; i < perimeter.size(); i++) {
         const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]);
-        vec2 nextNormal(next->y - current->y,
-                current->x - next->x);
+        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
         nextNormal.normalize();
 
-        vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
+        Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
         paintInfo.scaleOffsetForStrokeWidth(totalOffset);
 
         Vertex::set(&buffer[currentIndex++],
@@ -241,13 +238,14 @@
 }
 
 static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center,
-        const vec2& normal, Vertex* buffer, int& currentIndex, bool begin) {
-    vec2 strokeOffset = normal;
+        const Vector2& normal, Vertex* buffer, int& currentIndex, bool begin) {
+    Vector2 strokeOffset = normal;
     paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
 
-    vec2 referencePoint(center.x, center.y);
+    Vector2 referencePoint = {center.x, center.y};
     if (paintInfo.cap == SkPaint::kSquare_Cap) {
-        referencePoint += vec2(-strokeOffset.y, strokeOffset.x) * (begin ? -1 : 1);
+        Vector2 rotated = {-strokeOffset.y, strokeOffset.x};
+        referencePoint += rotated * (begin ? -1 : 1);
     }
 
     Vertex::set(&buffer[currentIndex++], referencePoint + strokeOffset);
@@ -288,14 +286,14 @@
             }
 
             beginTheta += dTheta;
-            vec2 beginRadialOffset(cos(beginTheta), sin(beginTheta));
+            Vector2 beginRadialOffset = {cos(beginTheta), sin(beginTheta)};
             paintInfo.scaleOffsetForStrokeWidth(beginRadialOffset);
             Vertex::set(&buffer[capOffset],
                     vertices[0].x + beginRadialOffset.x,
                     vertices[0].y + beginRadialOffset.y);
 
             endTheta += dTheta;
-            vec2 endRadialOffset(cos(endTheta), sin(endTheta));
+            Vector2 endRadialOffset = {cos(endTheta), sin(endTheta)};
             paintInfo.scaleOffsetForStrokeWidth(endRadialOffset);
             Vertex::set(&buffer[allocSize - 1 - capOffset],
                     vertices[lastIndex].x + endRadialOffset.x,
@@ -306,22 +304,20 @@
     int currentIndex = extra;
     const Vertex* last = &(vertices[0]);
     const Vertex* current = &(vertices[1]);
-    vec2 lastNormal(current->y - last->y,
-                last->x - current->x);
+    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
     lastNormal.normalize();
 
     storeBeginEnd(paintInfo, vertices[0], lastNormal, buffer, currentIndex, true);
 
     for (unsigned int i = 1; i < vertices.size() - 1; i++) {
         const Vertex* next = &(vertices[i + 1]);
-        vec2 nextNormal(next->y - current->y,
-                current->x - next->x);
+        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
         nextNormal.normalize();
 
-        vec2 strokeOffset  = totalOffsetFromNormals(lastNormal, nextNormal);
+        Vector2 strokeOffset  = totalOffsetFromNormals(lastNormal, nextNormal);
         paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
 
-        vec2 center(current->x, current->y);
+        Vector2 center = {current->x, current->y};
         Vertex::set(&buffer[currentIndex++], center + strokeOffset);
         Vertex::set(&buffer[currentIndex++], center - strokeOffset);
 
@@ -353,18 +349,16 @@
     int currentIndex = 0;
     const Vertex* last = &(perimeter[perimeter.size() - 1]);
     const Vertex* current = &(perimeter[0]);
-    vec2 lastNormal(current->y - last->y,
-            last->x - current->x);
+    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
     lastNormal.normalize();
     for (unsigned int i = 0; i < perimeter.size(); i++) {
         const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]);
-        vec2 nextNormal(next->y - current->y,
-                current->x - next->x);
+        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
         nextNormal.normalize();
 
         // AA point offset from original point is that point's normal, such that each side is offset
         // by .5 pixels
-        vec2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
+        Vector2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
 
         AlphaVertex::set(&buffer[currentIndex++],
                 current->x + totalOffset.x,
@@ -407,7 +401,7 @@
  * getStrokeVerticesFromUnclosedVerticesAA() below.
  */
 inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices,
-        AlphaVertex* buffer, bool isFirst, vec2 normal, int offset) {
+        AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
     const int extra = paintInfo.capExtraDivisions();
     const int extraOffset = (extra + 1) / 2;
     const int capIndex = isFirst
@@ -416,27 +410,28 @@
     if (isFirst) normal *= -1;
 
     // TODO: this normal should be scaled by radialScale if extra != 0, see totalOffsetFromNormals()
-    vec2 AAOffset = paintInfo.deriveAAOffset(normal);
+    Vector2 AAOffset = paintInfo.deriveAAOffset(normal);
 
-    vec2 strokeOffset = normal;
+    Vector2 strokeOffset = normal;
     paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
-    vec2 outerOffset = strokeOffset + AAOffset;
-    vec2 innerOffset = strokeOffset - AAOffset;
+    Vector2 outerOffset = strokeOffset + AAOffset;
+    Vector2 innerOffset = strokeOffset - AAOffset;
 
-    vec2 capAAOffset;
+    Vector2 capAAOffset = {0, 0};
     if (paintInfo.cap != SkPaint::kRound_Cap) {
         // if the cap is square or butt, the inside primary cap vertices will be inset in two
         // directions - both normal to the stroke, and parallel to it.
-        capAAOffset = vec2(-AAOffset.y, AAOffset.x);
+        capAAOffset = (Vector2){-AAOffset.y, AAOffset.x};
     }
 
     // determine referencePoint, the center point for the 4 primary cap vertices
     const Vertex* point = isFirst ? vertices.begin() : (vertices.end() - 1);
-    vec2 referencePoint(point->x, point->y);
+    Vector2 referencePoint = {point->x, point->y};
     if (paintInfo.cap == SkPaint::kSquare_Cap) {
         // To account for square cap, move the primary cap vertices (that create the AA edge) by the
         // stroke offset vector (rotated to be parallel to the stroke)
-        referencePoint += vec2(-strokeOffset.y, strokeOffset.x);
+        Vector2 rotated = {-strokeOffset.y, strokeOffset.x};
+        referencePoint += rotated;
     }
 
     AlphaVertex::set(&buffer[capIndex + 0],
@@ -469,7 +464,7 @@
         for (int i = 0; i < extra; i++) {
             theta += dTheta;
 
-            vec2 radialOffset(cos(theta), sin(theta));
+            Vector2 radialOffset = {cos(theta), sin(theta)};
 
             // scale to compensate for pinching at sharp angles, see totalOffsetFromNormals()
             radialOffset *= radialScale;
@@ -592,8 +587,7 @@
 
     const Vertex* last = &(vertices[0]);
     const Vertex* current = &(vertices[1]);
-    vec2 lastNormal(current->y - last->y,
-            last->x - current->x);
+    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
     lastNormal.normalize();
 
     // TODO: use normal from bezier traversal for cap, instead of from vertices
@@ -601,16 +595,15 @@
 
     for (unsigned int i = 1; i < vertices.size() - 1; i++) {
         const Vertex* next = &(vertices[i + 1]);
-        vec2 nextNormal(next->y - current->y,
-                current->x - next->x);
+        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
         nextNormal.normalize();
 
-        vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
-        vec2 AAOffset = paintInfo.deriveAAOffset(totalOffset);
+        Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
+        Vector2 AAOffset = paintInfo.deriveAAOffset(totalOffset);
 
-        vec2 innerOffset = totalOffset;
+        Vector2 innerOffset = totalOffset;
         paintInfo.scaleOffsetForStrokeWidth(innerOffset);
-        vec2 outerOffset = innerOffset + AAOffset;
+        Vector2 outerOffset = innerOffset + AAOffset;
         innerOffset -= AAOffset;
 
         AlphaVertex::set(&buffer[currentAAOuterIndex++],
@@ -662,21 +655,19 @@
 
     const Vertex* last = &(perimeter[perimeter.size() - 1]);
     const Vertex* current = &(perimeter[0]);
-    vec2 lastNormal(current->y - last->y,
-            last->x - current->x);
+    Vector2 lastNormal = {current->y - last->y, last->x - current->x};
     lastNormal.normalize();
     for (unsigned int i = 0; i < perimeter.size(); i++) {
         const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]);
-        vec2 nextNormal(next->y - current->y,
-                current->x - next->x);
+        Vector2 nextNormal = {next->y - current->y, current->x - next->x};
         nextNormal.normalize();
 
-        vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
-        vec2 AAOffset = paintInfo.deriveAAOffset(totalOffset);
+        Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
+        Vector2 AAOffset = paintInfo.deriveAAOffset(totalOffset);
 
-        vec2 innerOffset = totalOffset;
+        Vector2 innerOffset = totalOffset;
         paintInfo.scaleOffsetForStrokeWidth(innerOffset);
-        vec2 outerOffset = innerOffset + AAOffset;
+        Vector2 outerOffset = innerOffset + AAOffset;
         innerOffset -= AAOffset;
 
         AlphaVertex::set(&buffer[currentAAOuterIndex++],
@@ -794,16 +785,6 @@
     vertexBuffer.setBounds(bounds);
 }
 
-static void expandRectToCoverVertex(Rect& rect, float x, float y) {
-    rect.left = fminf(rect.left, x);
-    rect.top = fminf(rect.top, y);
-    rect.right = fmaxf(rect.right, x);
-    rect.bottom = fmaxf(rect.bottom, y);
-}
-static void expandRectToCoverVertex(Rect& rect, const Vertex& vertex) {
-    expandRectToCoverVertex(rect, vertex.x, vertex.y);
-}
-
 template <class TYPE>
 static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
         const float* points, int count, Rect& bounds) {
@@ -814,7 +795,7 @@
     dstBuffer.alloc<TYPE>(numPoints * verticesPerPoint + (numPoints - 1) * 2);
 
     for (int i = 0; i < count; i += 2) {
-        expandRectToCoverVertex(bounds, points[i + 0], points[i + 1]);
+        bounds.expandToCoverVertex(points[i + 0], points[i + 1]);
         dstBuffer.copyInto<TYPE>(srcBuffer, points[i + 0], points[i + 1]);
     }
     dstBuffer.createDegenerateSeparators<TYPE>(verticesPerPoint);
@@ -896,8 +877,8 @@
         }
 
         // calculate bounds
-        expandRectToCoverVertex(bounds, tempVerticesData[0]);
-        expandRectToCoverVertex(bounds, tempVerticesData[1]);
+        bounds.expandToCoverVertex(tempVerticesData[0].x, tempVerticesData[0].y);
+        bounds.expandToCoverVertex(tempVerticesData[1].x, tempVerticesData[1].y);
     }
 
     // since multiple objects tessellated into buffer, separate them with degen tris
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 846ebdc..9311f99 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -241,6 +241,13 @@
         bottom = ceilf(bottom);
     }
 
+    void expandToCoverVertex(float x, float y) {
+        left = fminf(left, x);
+        top = fminf(top, y);
+        right = fmaxf(right, x);
+        bottom = fmaxf(bottom, y);
+    }
+
     void dump(const char* label = NULL) const {
         ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
     }
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 3eb779f..01c7761 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -347,31 +347,35 @@
         }
     }
     const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
-    bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds();
+    int clipFlags = properties().getClippingFlags();
     if (properties().getAlpha() < 1) {
         if (isLayer) {
+            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+
             renderer.setOverrideLayerAlpha(properties().getAlpha());
         } else if (!properties().getHasOverlappingRendering()) {
             renderer.scaleAlpha(properties().getAlpha());
         } else {
-            // TODO: should be able to store the size of a DL at record time and not
-            // have to pass it into this call. In fact, this information might be in the
-            // location/size info that we store with the new native transform data.
+            Rect layerBounds(0, 0, getWidth(), getHeight());
             int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (clipToBoundsNeeded) {
+            if (clipFlags) {
                 saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
-                clipToBoundsNeeded = false; // clipping done by saveLayer
+                properties().getClippingRectForFlags(clipFlags, &layerBounds);
+                clipFlags = 0; // all clipping done by saveLayer
             }
 
             SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
-                    0, 0, properties().getWidth(), properties().getHeight(),
+                    layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom,
                     properties().getAlpha() * 255, saveFlags);
             handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
         }
     }
-    if (clipToBoundsNeeded) {
+    if (clipFlags) {
+        Rect clipRect;
+        properties().getClippingRectForFlags(clipFlags, &clipRect);
         ClipRectOp* op = new (handler.allocator()) ClipRectOp(
-                0, 0, properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op);
+                clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
+                SkRegion::kIntersect_Op);
         handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
     }
 
@@ -836,7 +840,8 @@
             DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
             const int saveCountOffset = renderer.getSaveCount() - 1;
             const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
-            for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+            const int size = static_cast<int>(mDisplayListData->displayListOps.size());
+            for (int i = 0; i < size; i++) {
                 DisplayListOp *op = mDisplayListData->displayListOps[i];
 
 #if DEBUG_DISPLAY_LIST
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 8848b2f..250cadc 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -75,7 +75,7 @@
 }
 
 RenderProperties::PrimitiveFields::PrimitiveFields()
-        : mClipToBounds(true)
+        : mClippingFlags(CLIP_TO_BOUNDS)
         , mProjectBackwards(false)
         , mProjectionReceiver(false)
         , mAlpha(1)
@@ -146,26 +146,34 @@
         }
     }
 
-    bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds;
+    const bool isLayer = layerProperties().type() != kLayerTypeNone;
+    int clipFlags = getClippingFlags();
     if (mPrimitiveFields.mAlpha < 1) {
-        if (layerProperties().type() != kLayerTypeNone) {
+        if (isLayer) {
+            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+
             ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
         } else if (!mPrimitiveFields.mHasOverlappingRendering) {
             ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
         } else {
-            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (clipToBoundsNeeded) {
-                flags |= SkCanvas::kClipToLayer_SaveFlag;
-                clipToBoundsNeeded = false; // clipping done by save layer
+            Rect layerBounds(0, 0, getWidth(), getHeight());
+            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
+            if (clipFlags) {
+                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
+                getClippingRectForFlags(clipFlags, &layerBounds);
+                clipFlags = 0; // all clipping done by saveLayer
             }
+
             ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
-                    0, 0, getWidth(), getHeight(),
-                    (int)(mPrimitiveFields.mAlpha * 255), flags);
+                    (int)layerBounds.left, (int)layerBounds.top, (int)layerBounds.right, (int)layerBounds.bottom,
+                    (int)(mPrimitiveFields.mAlpha * 255), saveFlags);
         }
     }
-    if (clipToBoundsNeeded) {
+    if (clipFlags) {
+        Rect clipRect;
+        getClippingRectForFlags(clipFlags, &clipRect);
         ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
-                0, 0, getWidth(), getHeight());
+                (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
     }
 }
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 227d56e..f50e514 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -58,6 +58,11 @@
     // TODO: LayerTypeSurfaceTexture? Maybe?
 };
 
+enum ClippingFlags {
+    CLIP_TO_BOUNDS =      0x1 << 0,
+    CLIP_TO_CLIP_BOUNDS = 0x1 << 1,
+};
+
 class ANDROID_API LayerProperties {
 public:
     bool setType(LayerType type) {
@@ -135,10 +140,35 @@
     RenderProperties();
     virtual ~RenderProperties();
 
+    static bool setFlag(int flag, bool newValue, int* outFlags) {
+        if (newValue) {
+            if (!(flag & *outFlags)) {
+                *outFlags |= flag;
+                return true;
+            }
+            return false;
+        } else {
+            if (flag & *outFlags) {
+                *outFlags &= ~flag;
+                return true;
+            }
+            return false;
+        }
+    }
+
     RenderProperties& operator=(const RenderProperties& other);
 
     bool setClipToBounds(bool clipToBounds) {
-        return RP_SET(mPrimitiveFields.mClipToBounds, clipToBounds);
+        return setFlag(CLIP_TO_BOUNDS, clipToBounds, &mPrimitiveFields.mClippingFlags);
+    }
+
+    bool setClipBounds(const Rect& clipBounds) {
+        bool ret = setFlag(CLIP_TO_CLIP_BOUNDS, true, &mPrimitiveFields.mClippingFlags);
+        return RP_SET(mPrimitiveFields.mClipBounds, clipBounds) || ret;
+    }
+
+    bool setClipBoundsEmpty() {
+        return setFlag(CLIP_TO_CLIP_BOUNDS, false, &mPrimitiveFields.mClippingFlags);
     }
 
     bool setProjectBackwards(bool shouldProject) {
@@ -433,7 +463,7 @@
         return false;
     }
 
-    bool offsetLeftRight(float offset) {
+    bool offsetLeftRight(int offset) {
         if (offset != 0) {
             mPrimitiveFields.mLeft += offset;
             mPrimitiveFields.mRight += offset;
@@ -442,7 +472,7 @@
         return false;
     }
 
-    bool offsetTopBottom(float offset) {
+    bool offsetTopBottom(int offset) {
         if (offset != 0) {
             mPrimitiveFields.mTop += offset;
             mPrimitiveFields.mBottom += offset;
@@ -477,8 +507,23 @@
         return mComputedFields.mTransformMatrix;
     }
 
+    int getClippingFlags() const {
+        return mPrimitiveFields.mClippingFlags;
+    }
+
     bool getClipToBounds() const {
-        return mPrimitiveFields.mClipToBounds;
+        return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS;
+    }
+
+    void getClippingRectForFlags(uint32_t flags, Rect* outRect) const {
+        if (flags & CLIP_TO_BOUNDS) {
+            outRect->set(0, 0, getWidth(), getHeight());
+            if (flags & CLIP_TO_CLIP_BOUNDS) {
+                outRect->intersect(mPrimitiveFields.mClipBounds);
+            }
+        } else {
+            outRect->set(mPrimitiveFields.mClipBounds);
+        }
     }
 
     bool getHasOverlappingRendering() const {
@@ -540,14 +585,13 @@
     }
 
 private:
-
     // Rendering properties
     struct PrimitiveFields {
         PrimitiveFields();
 
         Outline mOutline;
         RevealClip mRevealClip;
-        bool mClipToBounds;
+        int mClippingFlags;
         bool mProjectBackwards;
         bool mProjectionReceiver;
         float mAlpha;
@@ -561,6 +605,7 @@
         int mWidth, mHeight;
         bool mPivotExplicitlySet;
         bool mMatrixOrPivotDirty;
+        Rect mClipBounds;
     } mPrimitiveFields;
 
     SkMatrix* mStaticMatrix;
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index ccd3ba5..40a21e4 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -80,14 +80,6 @@
     virtual void setViewport(int width, int height) = 0;
 
     /**
-     * Sets the position and size of the spot shadow casting light.
-     *
-     * @param lightCenter The light's Y position, relative to the render target's top left
-     * @param lightRadius The light's radius
-     */
-    virtual void initializeLight(const Vector3& lightCenter, float lightRadius) = 0;
-
-    /**
      * Prepares the renderer to draw a frame. This method must be invoked
      * at the beginning of each frame. When this method is invoked, the
      * entire drawing surface is assumed to be redrawn.
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index bcfda99..e71439d 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -172,7 +172,8 @@
 
     Vector2 centroid = poly[0];
     if (area != 0) {
-        centroid = Vector2(sumx / (3 * area), sumy / (3 * area));
+        centroid = (Vector2){static_cast<float>(sumx / (3 * area)),
+            static_cast<float>(sumy / (3 * area))};
     } else {
         ALOGW("Area is 0 while computing centroid!");
     }
@@ -212,19 +213,19 @@
     while (SkPath::kDone_Verb != (v = iter.next(pts))) {
             switch (v) {
             case SkPath::kMove_Verb:
-                arrayForDirection.add(Vector2(pts[0].x(), pts[0].y()));
+                arrayForDirection.add((Vector2){pts[0].x(), pts[0].y()});
                 break;
             case SkPath::kLine_Verb:
-                arrayForDirection.add(Vector2(pts[1].x(), pts[1].y()));
+                arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
                 break;
             case SkPath::kQuad_Verb:
-                arrayForDirection.add(Vector2(pts[1].x(), pts[1].y()));
-                arrayForDirection.add(Vector2(pts[2].x(), pts[2].y()));
+                arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
+                arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
                 break;
             case SkPath::kCubic_Verb:
-                arrayForDirection.add(Vector2(pts[1].x(), pts[1].y()));
-                arrayForDirection.add(Vector2(pts[2].x(), pts[2].y()));
-                arrayForDirection.add(Vector2(pts[3].x(), pts[3].y()));
+                arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
+                arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
+                arrayForDirection.add((Vector2){pts[3].x(), pts[3].y()});
                 break;
             default:
                 break;
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 06f6204..8c3077b 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -218,7 +218,7 @@
 
     // Since neither polygon fully contain the other one, we need to add all the
     // intersection points.
-    Vector2 intersection;
+    Vector2 intersection = {0, 0};
     for (int i = 0; i < poly2Length; i++) {
         for (int j = 0; j < poly1Length; j++) {
             int poly2LineStart = i;
@@ -250,7 +250,7 @@
     }
 
     // Sort the result polygon around the center.
-    Vector2 center(0.0f, 0.0f);
+    Vector2 center = {0.0f, 0.0f};
     for (int i = 0; i < count; i++) {
         center += poly[i];
     }
@@ -507,7 +507,6 @@
     computeLightPolygon(lightVertexCount, lightCenter, lightSize, light);
     computeSpotShadow(isCasterOpaque, light, lightVertexCount, lightCenter, poly,
             polyLength, retStrips);
-    retStrips.setMode(VertexBuffer::kTwoPolyRingShadow);
 }
 
 /**
@@ -558,7 +557,7 @@
             float x = lightPoly[j].x - ratioZ * (lightPoly[j].x - poly[i].x);
             float y = lightPoly[j].y - ratioZ * (lightPoly[j].y - poly[i].y);
 
-            Vector2 newPoint = Vector2(x, y);
+            Vector2 newPoint = {x, y};
             shadowRegion[k] = newPoint;
             outline[m] = newPoint;
 
@@ -784,6 +783,9 @@
             shadowVertices[2 * rays + rayIndex] = centroidXYA;
         }
     }
+
+    shadowTriangleStrip.setMode(VertexBuffer::kTwoPolyRingShadow);
+    shadowTriangleStrip.computeBounds<AlphaVertex>();
 }
 
 /**
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 95c0ee5..140c6e8 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -23,10 +23,13 @@
 namespace android {
 namespace uirenderer {
 
-StatefulBaseRenderer::StatefulBaseRenderer() :
-        mDirtyClip(false), mWidth(-1), mHeight(-1),
-        mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot),
-        mLightCenter(FLT_MIN, FLT_MIN, FLT_MIN), mLightRadius(FLT_MIN) {
+StatefulBaseRenderer::StatefulBaseRenderer()
+        : mDirtyClip(false)
+        , mWidth(-1)
+        , mHeight(-1)
+        , mSaveCount(1)
+        , mFirstSnapshot(new Snapshot)
+        , mSnapshot(mFirstSnapshot) {
 }
 
 void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
@@ -45,11 +48,6 @@
     onViewportInitialized();
 }
 
-void StatefulBaseRenderer::initializeLight(const Vector3& lightCenter, float lightRadius) {
-    mLightCenter = lightCenter;
-    mLightRadius = lightRadius;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Save (layer)
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index e8e024f..25cc832 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -52,7 +52,6 @@
      * the render target.
      */
     virtual void setViewport(int width, int height);
-    virtual void initializeLight(const Vector3& lightCenter, float lightRadius);
     void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom);
 
     // getters
@@ -161,10 +160,6 @@
     // Current state
     // TODO: should become private, once hooks needed by OpenGLRenderer are added
     sp<Snapshot> mSnapshot;
-
-    Vector3 mLightCenter;
-    float mLightRadius;
-
 }; // class StatefulBaseRenderer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 08b54ff..c5fc21f 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -125,7 +125,7 @@
     }
 };
 
-struct TessellationCache::Buffer {
+class TessellationCache::Buffer {
 public:
     Buffer(const sp<Task<VertexBuffer*> >& task)
             : mTask(task)
@@ -236,7 +236,7 @@
     float maxZ = -FLT_MAX;
     for (int i = 0; i < casterVertexCount; i++) {
         const Vertex& point2d = casterVertices2d[i];
-        casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
+        casterPolygon[i] = (Vector3){point2d.x, point2d.y, 0};
         mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
         minZ = fmin(minZ, casterPolygon[i].z);
         maxZ = fmax(maxZ, casterPolygon[i].z);
@@ -246,7 +246,7 @@
     Vector2 centroid =  ShadowTessellator::centroid2d(
             reinterpret_cast<const Vector2*>(casterVertices2d.array()),
             casterVertexCount);
-    Vector3 centroid3d(centroid.x, centroid.y, 0);
+    Vector3 centroid3d = {centroid.x, centroid.y, 0};
     mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
 
     // if the caster intersects the z=0 plane, lift it in Z so it doesn't
@@ -273,8 +273,6 @@
             isCasterOpaque, casterPolygon, casterVertexCount,
             *drawTransform, lightCenter, lightRadius, casterBounds, *localClip,
             spotBuffer);
-
-    // TODO: set ambientBuffer & spotBuffer's bounds for correct layer damage
 }
 
 class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t*> {
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index c61cb61..2a9f01c 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -24,18 +24,11 @@
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
 
+// MUST BE A POD - this means no ctor or dtor!
 struct Vector2 {
     float x;
     float y;
 
-    Vector2() :
-        x(0.0f), y(0.0f) {
-    }
-
-    Vector2(float px, float py) :
-        x(px), y(py) {
-    }
-
     float lengthSquared() const {
         return x * x + y * y;
     }
@@ -75,19 +68,19 @@
     }
 
     Vector2 operator+(const Vector2& v) const {
-        return Vector2(x + v.x, y + v.y);
+        return (Vector2){x + v.x, y + v.y};
     }
 
     Vector2 operator-(const Vector2& v) const {
-        return Vector2(x - v.x, y - v.y);
+        return (Vector2){x - v.x, y - v.y};
     }
 
     Vector2 operator/(float s) const {
-        return Vector2(x / s, y / s);
+        return (Vector2){x / s, y / s};
     }
 
     Vector2 operator*(float s) const {
-        return Vector2(x * s, y * s);
+        return (Vector2){x * s, y * s};
     }
 
     void normalize() {
@@ -97,7 +90,7 @@
     }
 
     Vector2 copyNormalized() const {
-        Vector2 v(x, y);
+        Vector2 v = {x, y};
         v.normalize();
         return v;
     }
@@ -111,31 +104,18 @@
     }
 }; // class Vector2
 
+// MUST BE A POD - this means no ctor or dtor!
 class Vector3 {
 public:
     float x;
     float y;
     float z;
 
-    Vector3() :
-        x(0.0f), y(0.0f), z(0.0f) {
-    }
-
-    Vector3(float px, float py, float pz) :
-        x(px), y(py), z(pz) {
-    }
-
     void dump() {
         ALOGD("Vector3[%.2f, %.2f, %.2f]", x, y, z);
     }
 };
 
-///////////////////////////////////////////////////////////////////////////////
-// Types
-///////////////////////////////////////////////////////////////////////////////
-
-typedef Vector2 vec2;
-
 }; // namespace uirenderer
 }; // namespace android
 
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 5d7a199..4ff0b18 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -43,7 +43,7 @@
         vertex[0].y = y;
     }
 
-    static inline void set(Vertex* vertex, vec2 val) {
+    static inline void set(Vertex* vertex, Vector2 val) {
         set(vertex, val.x, val.y);
     }
 
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index 55d566b..3837f88 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -62,6 +62,7 @@
         mVertexCount = vertexCount;
         mByteCount = mVertexCount * sizeof(TYPE);
         mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
+
         mCleanupMethod = &(cleanup<TYPE>);
 
         return (TYPE*)mBuffer;
@@ -79,6 +80,28 @@
         }
     }
 
+    /**
+     * Brute force bounds computation, used only if the producer of this
+     * vertex buffer can't determine bounds more simply/efficiently
+     */
+    template <class TYPE>
+    void computeBounds(int vertexCount = 0) {
+        if (!mVertexCount) {
+            mBounds.setEmpty();
+            return;
+        }
+
+        // default: compute over every vertex
+        if (vertexCount == 0) vertexCount = mVertexCount;
+
+        TYPE* current = (TYPE*)mBuffer;
+        TYPE* end = current + vertexCount;
+        mBounds.set(current->x, current->y, current->x, current->y);
+        for (; current < end; current++) {
+            mBounds.expandToCoverVertex(current->x, current->y);
+        }
+    }
+
     const void* getBuffer() const { return mBuffer; }
     const Rect& getBounds() const { return mBounds; }
     unsigned int getVertexCount() const { return mVertexCount; }
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 2147810..756f660 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -110,10 +110,11 @@
     // and such to prevent from trying to render into this surface
 }
 
-void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius) {
+void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
+        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
     if (!mCanvas) return;
     mCanvas->setViewport(width, height);
-    mCanvas->initializeLight(lightCenter, lightRadius);
+    mCanvas->initLight(lightCenter, lightRadius, ambientShadowAlpha, spotShadowAlpha);
 }
 
 void CanvasContext::setOpaque(bool opaque) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 1bab1b1..2a01027 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -53,7 +53,8 @@
     bool initialize(ANativeWindow* window);
     void updateSurface(ANativeWindow* window);
     void pauseSurface(ANativeWindow* window);
-    void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
+    void setup(int width, int height, const Vector3& lightCenter, float lightRadius,
+            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     void setOpaque(bool opaque);
     void makeCurrent();
     void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 6cd3d0b..3f03093 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -39,6 +39,8 @@
 #define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
 #define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,)
 #define CREATE_BRIDGE5(name, a1, a2, a3, a4, a5) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,,,)
+#define CREATE_BRIDGE6(name, a1, a2, a3, a4, a5, a6) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,,)
+#define CREATE_BRIDGE7(name, a1, a2, a3, a4, a5, a6, a7) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,a7,)
 #define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \
     typedef struct { \
         a1; a2; a3; a4; a5; a6; a7; a8; \
@@ -152,19 +154,24 @@
     postAndWait(task);
 }
 
-CREATE_BRIDGE5(setup, CanvasContext* context, int width, int height,
-        Vector3 lightCenter, int lightRadius) {
-    args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius);
+CREATE_BRIDGE7(setup, CanvasContext* context, int width, int height,
+        Vector3 lightCenter, float lightRadius,
+        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+    args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius,
+            args->ambientShadowAlpha, args->spotShadowAlpha);
     return NULL;
 }
 
-void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius) {
+void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
+        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
     SETUP_TASK(setup);
     args->context = mContext;
     args->width = width;
     args->height = height;
     args->lightCenter = lightCenter;
     args->lightRadius = lightRadius;
+    args->ambientShadowAlpha = ambientShadowAlpha;
+    args->spotShadowAlpha = spotShadowAlpha;
     post(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 0027403..28d0173 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -67,7 +67,8 @@
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
-    ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
+    ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius,
+            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     ANDROID_API void setOpaque(bool opaque);
     ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
             float density);
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 65f1663..2dfe9c6 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -19,19 +19,19 @@
 namespace android {
 namespace uirenderer {
 
+#define NON_ZERO_EPSILON (0.001f)
+
 class MathUtils {
-private:
-    static const float gNonZeroEpsilon = 0.001f;
 public:
     /**
      * Check for floats that are close enough to zero.
      */
     inline static bool isZero(float value) {
-        return (value >= -gNonZeroEpsilon) && (value <= gNonZeroEpsilon);
+        return (value >= -NON_ZERO_EPSILON) && (value <= NON_ZERO_EPSILON);
     }
 
     inline static bool isPositive(float value) {
-        return value >= gNonZeroEpsilon;
+        return value >= NON_ZERO_EPSILON;
     }
 
     inline static bool areEqual(float valueA, float valueB) {
diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementListenerTransport.java
index 48a4b44..2d9a372 100644
--- a/location/java/android/location/GpsMeasurementListenerTransport.java
+++ b/location/java/android/location/GpsMeasurementListenerTransport.java
@@ -16,99 +16,51 @@
 
 package android.location;
 
-import com.android.internal.util.Preconditions;
-
-import android.annotation.NonNull;
 import android.content.Context;
 import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
 
 /**
- * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener},
- * and post the events in a handler.
+ * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}.
  *
  * @hide
  */
-class GpsMeasurementListenerTransport {
-    private static final String TAG = "GpsMeasurementListenerTransport";
-
+class GpsMeasurementListenerTransport
+        extends LocalListenerHelper<GpsMeasurementsEvent.Listener> {
     private final Context mContext;
     private final ILocationManager mLocationManager;
 
     private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
-    private final HashSet<GpsMeasurementsEvent.Listener> mListeners =
-            new HashSet<GpsMeasurementsEvent.Listener>();
 
     public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
+        super("GpsMeasurementListenerTransport");
         mContext = context;
         mLocationManager = locationManager;
     }
 
-    public boolean add(@NonNull GpsMeasurementsEvent.Listener listener) {
-        Preconditions.checkNotNull(listener);
-
-        synchronized (mListeners) {
-            // we need to register with the service first, because we need to find out if the
-            // service will actually support the request before we attempt anything
-            if (mListeners.isEmpty()) {
-                boolean registeredWithServer;
-                try {
-                    registeredWithServer = mLocationManager.addGpsMeasurementsListener(
-                            mListenerTransport,
-                            mContext.getPackageName());
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error handling first listener.", e);
-                    return false;
-                }
-
-                if (!registeredWithServer) {
-                    Log.e(TAG, "Unable to register listener transport.");
-                    return false;
-                }
-            }
-
-            if (mListeners.contains(listener)) {
-                return true;
-            }
-
-            mListeners.add(listener);
-        }
-
-        return true;
+    @Override
+    protected boolean registerWithServer() throws RemoteException {
+        return mLocationManager.addGpsMeasurementsListener(
+                mListenerTransport,
+                mContext.getPackageName());
     }
 
-    public void remove(@NonNull GpsMeasurementsEvent.Listener listener) {
-        Preconditions.checkNotNull(listener);
-
-        synchronized (mListeners) {
-            boolean removed = mListeners.remove(listener);
-
-            boolean isLastListener = removed && mListeners.isEmpty();
-            if (isLastListener) {
-                try {
-                    mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error handling last listener.", e);
-                }
-            }
-        }
+    @Override
+    protected void unregisterFromServer() throws RemoteException {
+        mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
     }
 
     private class ListenerTransport extends IGpsMeasurementsListener.Stub {
         @Override
-        public void onGpsMeasurementsReceived(final GpsMeasurementsEvent eventArgs) {
-            Collection<GpsMeasurementsEvent.Listener> listeners;
-            synchronized (mListeners) {
-                listeners = new ArrayList<GpsMeasurementsEvent.Listener>(mListeners);
-            }
+        public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) {
+            ListenerOperation<GpsMeasurementsEvent.Listener> operation =
+                    new ListenerOperation<GpsMeasurementsEvent.Listener>() {
+                @Override
+                public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
+                    listener.onGpsMeasurementsReceived(event);
+                }
+            };
 
-            for (final GpsMeasurementsEvent.Listener listener : listeners) {
-                listener.onGpsMeasurementsReceived(eventArgs);
-            }
+            foreach(operation);
         }
     }
 }
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
new file mode 100644
index 0000000..2eb4708
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A class containing a GPS satellite Navigation Message.
+ *
+ * @hide
+ */
+public class GpsNavigationMessage implements Parcelable {
+    private static final String TAG = "GpsNavigationMessage";
+    private static final byte[] EMPTY_ARRAY = new byte[0];
+
+    // The following enumerations must be in sync with the values declared in gps.h
+
+    /**
+     * The type of the navigation message is not available or unknown.
+     */
+    public static final byte TYPE_UNKNOWN = 0;
+
+    /**
+     * The Navigation Message is of type L1 C/A.
+     */
+    public static final byte TYPE_L1CA = 1;
+
+    /**
+     * The Navigation Message is of type L1-CNAV.
+     */
+    public static final byte TYPE_L2CNAV = 2;
+
+    /**
+     * The Navigation Message is of type L5-CNAV.
+     */
+    public static final byte TYPE_L5CNAV = 3;
+
+    /**
+     * The Navigation Message is of type CNAV-2.
+     */
+    public static final byte TYPE_CNAV2 = 4;
+
+    // End enumerations in sync with gps.h
+
+    private byte mType;
+    private byte mPrn;
+    private short mMessageId;
+    private short mSubmessageId;
+    private byte[] mData;
+
+    GpsNavigationMessage() {
+        initialize();
+    }
+
+    /**
+     * Sets all contents to the values stored in the provided object.
+     */
+    public void set(GpsNavigationMessage navigationMessage) {
+        mType = navigationMessage.mType;
+        mPrn = navigationMessage.mPrn;
+        mMessageId = navigationMessage.mMessageId;
+        mSubmessageId = navigationMessage.mSubmessageId;
+        mData = navigationMessage.mData;
+    }
+
+    /**
+     * Resets all the contents to its original state.
+     */
+    public void reset() {
+        initialize();
+    }
+
+    /**
+     * Gets the type of the navigation message contained in the object.
+     */
+    public byte getType() {
+        return mType;
+    }
+
+    /**
+     * Sets the type of the navigation message.
+     */
+    public void setType(byte value) {
+        switch (value) {
+            case TYPE_UNKNOWN:
+            case TYPE_L1CA:
+            case TYPE_L2CNAV:
+            case TYPE_L5CNAV:
+            case TYPE_CNAV2:
+                mType = value;
+                break;
+            default:
+                Log.d(TAG, "Sanitizing invalid 'type': " + value);
+                mType = TYPE_UNKNOWN;
+                break;
+        }
+    }
+
+    /**
+     * Gets a string representation of the 'type'.
+     * For internal and logging use only.
+     */
+    private String getTypeString() {
+        switch (mType) {
+            case TYPE_UNKNOWN:
+                return "Unknown";
+            case TYPE_L1CA:
+                return "L1 C/A";
+            case TYPE_L2CNAV:
+                return "L2-CNAV";
+            case TYPE_L5CNAV:
+                return "L5-CNAV";
+            case TYPE_CNAV2:
+                return "CNAV-2";
+            default:
+                return "<Invalid>";
+        }
+    }
+
+    /**
+     * Gets the Pseudo-random number.
+     * Range: [1, 32].
+     */
+    public byte getPrn() {
+        return mPrn;
+    }
+
+    /**
+     * Sets the Pseud-random number.
+     */
+    public void setPrn(byte value) {
+        mPrn = value;
+    }
+
+    /**
+     * Gets the Message Identifier.
+     * It provides an index so the complete Navigation Message can be assembled. i.e. for L1 C/A
+     * subframe 4 and 5, this value corresponds to the 'frame id' of the navigation message.
+     * Subframe 1, 2, 3 does not contain a 'frame id' and this might be reported as -1.
+     */
+    public short getMessageId() {
+        return mMessageId;
+    }
+
+    /**
+     * Sets the Message Identifier.
+     */
+    public void setMessageId(short value) {
+        mMessageId = value;
+    }
+
+    /**
+     * Gets the Sub-message Identifier.
+     * If required by {@link #getType()}, this value contains a sub-index within the current message
+     * (or frame) that is being transmitted. i.e. for L1 C/A the sub-message identifier corresponds
+     * to the sub-frame Id of the navigation message.
+     */
+    public short getSubmessageId() {
+        return mSubmessageId;
+    }
+
+    /**
+     * Sets the Sub-message identifier.
+     */
+    public void setSubmessageId(short value) {
+        mSubmessageId = value;
+    }
+
+    /**
+     * Gets the data associated with the Navigation Message.
+     * The bytes (or words) specified using big endian format (MSB first).
+     */
+    @NonNull
+    public byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * Sets the data associated with the Navigation Message.
+     */
+    public void setData(byte[] value) {
+        if (value == null) {
+            throw new InvalidParameterException("Data must be a non-null array");
+        }
+
+        mData = value;
+    }
+
+    public static final Creator<GpsNavigationMessage> CREATOR =
+            new Creator<GpsNavigationMessage>() {
+        @Override
+        public GpsNavigationMessage createFromParcel(Parcel parcel) {
+            GpsNavigationMessage navigationMessage = new GpsNavigationMessage();
+
+            navigationMessage.setType(parcel.readByte());
+            navigationMessage.setPrn(parcel.readByte());
+            navigationMessage.setMessageId((short) parcel.readInt());
+            navigationMessage.setSubmessageId((short) parcel.readInt());
+
+            int dataLength = parcel.readInt();
+            byte[] data = new byte[dataLength];
+            parcel.readByteArray(data);
+            navigationMessage.setData(data);
+
+            return navigationMessage;
+        }
+
+        @Override
+        public GpsNavigationMessage[] newArray(int size) {
+            return new GpsNavigationMessage[size];
+        }
+    };
+
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeByte(mType);
+        parcel.writeByte(mPrn);
+        parcel.writeInt(mMessageId);
+        parcel.writeInt(mSubmessageId);
+        parcel.writeInt(mData.length);
+        parcel.writeByteArray(mData);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        final String format = "   %-15s = %s\n";
+        StringBuilder builder = new StringBuilder("GpsNavigationMessage:\n");
+
+        builder.append(String.format(format, "Type", getTypeString()));
+        builder.append(String.format(format, "Prn", mPrn));
+        builder.append(String.format(format, "MessageId", mMessageId));
+        builder.append(String.format(format, "SubmessageId", mSubmessageId));
+
+        builder.append(String.format(format, "Data", "{"));
+        String prefix = "        ";
+        for(byte value : mData) {
+            builder.append(prefix);
+            builder.append(value);
+            prefix = ", ";
+        }
+        builder.append(" }");
+
+        return builder.toString();
+    }
+
+    private void initialize() {
+        mType = TYPE_UNKNOWN;
+        mPrn = 0;
+        mMessageId = -1;
+        mSubmessageId = -1;
+        mData = EMPTY_ARRAY;
+    }
+}
diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/location/java/android/location/GpsNavigationMessageEvent.aidl
similarity index 68%
copy from core/java/android/service/dreams/IDozeHardware.aidl
copy to location/java/android/location/GpsNavigationMessageEvent.aidl
index f5a657b..f84c2f7 100644
--- a/core/java/android/service/dreams/IDozeHardware.aidl
+++ b/location/java/android/location/GpsNavigationMessageEvent.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.dreams;
+package android.location;
 
-/**
- * @hide
- */
-interface IDozeHardware {
-    byte[] sendMessage(String msg, in byte[] arg);
-}
+parcelable GpsNavigationMessageEvent;
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
new file mode 100644
index 0000000..50ffa75
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.security.InvalidParameterException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * A class implementing a container for data associated with a navigation message event.
+ * Events are delivered to registered instances of {@link Listener}.
+ *
+ * @hide
+ */
+public class GpsNavigationMessageEvent implements Parcelable {
+    private final GpsNavigationMessage mNavigationMessage;
+
+    /**
+     * Used for receiving GPS satellite Navigation Messages from the GPS engine.
+     * You can implement this interface and call
+     * {@link LocationManager#addGpsNavigationMessageListener}.
+     *
+     * @hide
+     */
+    public interface Listener {
+        void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event);
+    }
+
+    public GpsNavigationMessageEvent(GpsNavigationMessage message) {
+        if (message == null) {
+            throw new InvalidParameterException("Parameter 'message' must not be null.");
+        }
+        mNavigationMessage = message;
+    }
+
+    @NonNull
+    public GpsNavigationMessage getNavigationMessage() {
+        return mNavigationMessage;
+    }
+
+    public static final Creator<GpsNavigationMessageEvent> CREATOR =
+            new Creator<GpsNavigationMessageEvent>() {
+                @Override
+                public GpsNavigationMessageEvent createFromParcel(Parcel in) {
+                    ClassLoader classLoader = getClass().getClassLoader();
+                    GpsNavigationMessage navigationMessage = in.readParcelable(classLoader);
+                    return new GpsNavigationMessageEvent(navigationMessage);
+                }
+
+                @Override
+                public GpsNavigationMessageEvent[] newArray(int size) {
+                    return new GpsNavigationMessageEvent[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mNavigationMessage, flags);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("[ GpsNavigationMessageEvent:\n\n");
+        builder.append(mNavigationMessage.toString());
+        builder.append("\n]");
+        return builder.toString();
+    }
+}
diff --git a/location/java/android/location/GpsNavigationMessageListenerTransport.java b/location/java/android/location/GpsNavigationMessageListenerTransport.java
new file mode 100644
index 0000000..ec4812b
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageListenerTransport.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import android.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A handler class to manage transport listeners for {@link GpsNavigationMessageEvent.Listener}.
+ *
+ * @hide
+ */
+class GpsNavigationMessageListenerTransport
+        extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> {
+    private final Context mContext;
+    private final ILocationManager mLocationManager;
+
+    private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
+
+    public GpsNavigationMessageListenerTransport(
+            Context context,
+            ILocationManager locationManager) {
+        super("GpsNavigationMessageListenerTransport");
+        mContext = context;
+        mLocationManager = locationManager;
+    }
+
+    @Override
+    protected boolean registerWithServer() throws RemoteException {
+        return mLocationManager.addGpsNavigationMessageListener(
+                mListenerTransport,
+                mContext.getPackageName());
+    }
+
+    @Override
+    protected void unregisterFromServer() throws RemoteException {
+        mLocationManager.removeGpsNavigationMessageListener(mListenerTransport);
+    }
+
+    private class ListenerTransport extends IGpsNavigationMessageListener.Stub {
+        @Override
+        public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) {
+            ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
+                    new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
+                @Override
+                public void execute(GpsNavigationMessageEvent.Listener listener)
+                        throws RemoteException {
+                    listener.onGpsNavigationMessageReceived(event);
+                }
+            };
+
+            foreach(operation);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/location/java/android/location/IGpsNavigationMessageListener.aidl
similarity index 66%
copy from packages/DocumentsUI/res/drawable/ic_doc_audio.xml
copy to location/java/android/location/IGpsNavigationMessageListener.aidl
index c6ccea6..18603fe 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/location/java/android/location/IGpsNavigationMessageListener.aidl
@@ -1,7 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
 /*
- * Copyright 2013, The Android Open Source Project
+ * 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.
@@ -15,9 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
--->
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_audio_am"
-        android:autoMirrored="true">
-</bitmap>
\ No newline at end of file
+package android.location;
+
+import android.location.GpsNavigationMessageEvent;
+
+/**
+ * {@hide}
+ */
+oneway interface IGpsNavigationMessageListener {
+    void onGpsNavigationMessageReceived(in GpsNavigationMessageEvent event);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index a1acaf1..1501710 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -22,6 +22,7 @@
 import android.location.GeocoderParams;
 import android.location.Geofence;
 import android.location.IGpsMeasurementsListener;
+import android.location.IGpsNavigationMessageListener;
 import android.location.IGpsStatusListener;
 import android.location.ILocationListener;
 import android.location.Location;
@@ -63,6 +64,11 @@
     boolean addGpsMeasurementsListener(in IGpsMeasurementsListener listener, in String packageName);
     boolean removeGpsMeasurementsListener(in IGpsMeasurementsListener listener);
 
+    boolean addGpsNavigationMessageListener(
+            in IGpsNavigationMessageListener listener,
+            in String packageName);
+    boolean removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
+
     // --- deprecated ---
     List<String> getAllProviders();
     List<String> getProviders(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java
new file mode 100644
index 0000000..1f3bf67
--- /dev/null
+++ b/location/java/android/location/LocalListenerHelper.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import com.android.internal.util.Preconditions;
+
+import android.annotation.NonNull;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * A base handler class to manage transport and local listeners.
+ *
+ * @hide
+ */
+abstract class LocalListenerHelper<TListener> {
+    private final HashSet<TListener> mListeners = new HashSet<TListener>();
+    private final String mTag;
+
+    protected LocalListenerHelper(String name) {
+        Preconditions.checkNotNull(name);
+        mTag = name;
+    }
+
+    public boolean add(@NonNull TListener listener) {
+        Preconditions.checkNotNull(listener);
+
+        synchronized (mListeners) {
+            // we need to register with the service first, because we need to find out if the
+            // service will actually support the request before we attempt anything
+            if (mListeners.isEmpty()) {
+                boolean registeredWithService;
+                try {
+                    registeredWithService = registerWithServer();
+                } catch (RemoteException e) {
+                    Log.e(mTag, "Error handling first listener.", e);
+                    return false;
+                }
+                if (!registeredWithService) {
+                    Log.e(mTag, "Unable to register listener transport.");
+                    return false;
+                }
+            }
+
+            if (mListeners.contains(listener)) {
+                return true;
+            }
+            mListeners.add(listener);
+        }
+        return true;
+    }
+
+    public void remove(@NonNull TListener listener) {
+        Preconditions.checkNotNull(listener);
+
+        synchronized (mListeners) {
+            boolean removed = mListeners.remove(listener);
+            boolean isLastRemoved = removed && mListeners.isEmpty();
+            if (isLastRemoved) {
+                try {
+                    unregisterFromServer();
+                } catch (RemoteException e) {
+
+                }
+            }
+        }
+    }
+
+    protected abstract boolean registerWithServer() throws RemoteException;
+    protected abstract void unregisterFromServer() throws RemoteException;
+
+    protected interface ListenerOperation<TListener> {
+        void execute(TListener listener) throws RemoteException;
+    }
+
+    protected void foreach(ListenerOperation operation) {
+        Collection<TListener> listeners;
+        synchronized (mListeners) {
+            listeners = new ArrayList<TListener>(mListeners);
+        }
+
+        for (TListener listener : listeners) {
+            try {
+                operation.execute(listener);
+            } catch (RemoteException e) {
+                Log.e(mTag, "Error in monitored listener.", e);
+                // don't return, give a fair chance to all listeners to receive the event
+            }
+        }
+    }
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index d6a8fb8..082a158 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -59,6 +59,7 @@
     private final Context mContext;
     private final ILocationManager mService;
     private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
+    private final GpsNavigationMessageListenerTransport mGpsNavigationMessageListenerTransport;
     private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
             new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
     private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
@@ -310,6 +311,8 @@
         mService = service;
         mContext = context;
         mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
+        mGpsNavigationMessageListenerTransport =
+                new GpsNavigationMessageListenerTransport(mContext, mService);
     }
 
     private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1573,7 +1576,7 @@
     /**
      * Adds a GPS Measurement listener.
      *
-     * @param listener a {@link android.location.GpsMeasurementsEvent.Listener} object to register.
+     * @param listener a {@link GpsMeasurementsEvent.Listener} object to register.
      * @return {@code true} if the listener was successfully registered, {@code false} otherwise.
      *
      * @hide
@@ -1593,6 +1596,30 @@
         mGpsMeasurementListenerTransport.remove(listener);
     }
 
+    /**
+     * Adds a GPS Navigation Message listener.
+     *
+     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.
+     * @return {@code true} if the listener was successfully registered, {@code false} otherwise.
+     *
+     * @hide
+     */
+    public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
+        return mGpsNavigationMessageListenerTransport.add(listener);
+    }
+
+    /**
+     * Removes a GPS Navigation Message listener.
+     *
+     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove.
+     *
+     * @hide
+     */
+    public void removeGpsNavigationMessageListener(
+            GpsNavigationMessageEvent.Listener listener) {
+        mGpsNavigationMessageListenerTransport.remove(listener);
+    }
+
      /**
      * Retrieves information about the current status of the GPS engine.
      * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 52608a9..1116127 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -27,7 +27,10 @@
 import android.media.RemoteController.OnClientUpdateListener;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
 import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.MediaSessionManager;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -354,6 +357,12 @@
     public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
 
     /**
+     * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
+     * @hide
+     */
+    public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
+
+    /**
      * Ringer mode that will be silent and will not vibrate. (This overrides the
      * vibrate setting.)
      *
@@ -2212,7 +2221,9 @@
      *      that will receive the media button intent. This broadcast receiver must be declared
      *      in the application manifest. The package of the component must match that of
      *      the context you're registering from.
+     * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
      */
+    @Deprecated
     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2238,9 +2249,12 @@
      * you know you will continue running for the full time until unregistering the
      * PendingIntent.
      * @param eventReceiver target that will receive media button intents.  The PendingIntent
-     * will be sent as-is when a media button action occurs, with {@link Intent#EXTRA_KEY_EVENT}
-     * added and holding the key code of the media button that was pressed.
+     * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
+     * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
+     * media button that was pressed.
+     * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
      */
+    @Deprecated
     public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2265,7 +2279,9 @@
      * Unregister the receiver of MEDIA_BUTTON intents.
      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
      *      that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2283,7 +2299,9 @@
      * Unregister the receiver of MEDIA_BUTTON intents.
      * @param eventReceiver same PendingIntent that was registed with
      *      {@link #registerMediaButtonEventReceiver(PendingIntent)}.
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2305,7 +2323,9 @@
      * @param rcClient The remote control client from which remote controls will receive
      *      information to display.
      * @see RemoteControlClient
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void registerRemoteControlClient(RemoteControlClient rcClient) {
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
@@ -2318,7 +2338,9 @@
      * remote controls.
      * @param rcClient The remote control client to unregister.
      * @see #registerRemoteControlClient(RemoteControlClient)
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
@@ -2336,7 +2358,11 @@
      * @param rctlr the object to register.
      * @return true if the {@link RemoteController} was successfully registered, false if an
      *     error occurred, due to an internal system error, or insufficient permissions.
+     * @deprecated Use
+     * {@link MediaSessionManager#addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, ComponentName)}
+     * and {@link MediaController} instead.
      */
+    @Deprecated
     public boolean registerRemoteController(RemoteController rctlr) {
         if (rctlr == null) {
             return false;
@@ -2349,7 +2375,11 @@
      * Unregisters a {@link RemoteController}, causing it to no longer receive media metadata and
      * playback state information, and no longer be capable of controlling playback.
      * @param rctlr the object to unregister.
+     * @deprecated Use
+     * {@link MediaSessionManager#removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener)}
+     * instead.
      */
+    @Deprecated
     public void unregisterRemoteController(RemoteController rctlr) {
         if (rctlr == null) {
             return;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ef42549..ae7c501 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -44,6 +44,7 @@
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiTvClient;
 import android.hardware.usb.UsbManager;
 import android.media.MediaPlayer.OnCompletionListener;
@@ -70,6 +71,7 @@
 import android.telecomm.TelecommManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.Slog;
 import android.view.KeyEvent;
 import android.view.Surface;
@@ -144,7 +146,23 @@
     private final Context mContext;
     private final ContentResolver mContentResolver;
     private final AppOpsManager mAppOps;
-    private final boolean mVoiceCapable;
+
+    // the platform has no specific capabilities
+    private static final int PLATFORM_DEFAULT = 0;
+    // the platform is voice call capable (a phone)
+    private static final int PLATFORM_VOICE = 1;
+    // the platform is a television or a set-top box
+    private static final int PLATFORM_TELEVISION = 2;
+    // the platform type affects volume and silent mode behavior
+    private final int mPlatformType;
+
+    private boolean isPlatformVoice() {
+        return mPlatformType == PLATFORM_VOICE;
+    }
+
+    private boolean isPlatformTelevision() {
+        return mPlatformType == PLATFORM_TELEVISION;
+    }
 
     /** The controller for the volume UI. */
     private final VolumeController mVolumeController = new VolumeController();
@@ -180,6 +198,7 @@
     private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
     private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
     private static final int MSG_SYSTEM_READY = 21;
+    private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -243,9 +262,10 @@
      * NOTE: do not create loops in aliases!
      * Some streams alias to different streams according to device category (phone or tablet) or
      * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
-     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
-     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
-    private final int[] STREAM_VOLUME_ALIAS = new int[] {
+     *  mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
+     *  (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
+     *  STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
+    private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
         AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
         AudioSystem.STREAM_RING,            // STREAM_SYSTEM
         AudioSystem.STREAM_RING,            // STREAM_RING
@@ -257,7 +277,19 @@
         AudioSystem.STREAM_RING,            // STREAM_DTMF
         AudioSystem.STREAM_MUSIC            // STREAM_TTS
     };
-    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
+    private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
+        AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
+        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM
+        AudioSystem.STREAM_MUSIC,       // STREAM_RING
+        AudioSystem.STREAM_MUSIC,       // STREAM_MUSIC
+        AudioSystem.STREAM_MUSIC,       // STREAM_ALARM
+        AudioSystem.STREAM_MUSIC,       // STREAM_NOTIFICATION
+        AudioSystem.STREAM_MUSIC,       // STREAM_BLUETOOTH_SCO
+        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
+        AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
+        AudioSystem.STREAM_MUSIC        // STREAM_TTS
+    };
+    private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
         AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
         AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
         AudioSystem.STREAM_RING,            // STREAM_RING
@@ -455,9 +487,12 @@
     public final static int STREAM_REMOTE_MUSIC = -200;
 
     // Devices for which the volume is fixed and VolumePanel slider should be disabled
-    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
+    int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
             AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
-            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
+            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
+            AudioSystem.DEVICE_OUT_HDMI_ARC |
+            AudioSystem.DEVICE_OUT_SPDIF |
+            AudioSystem.DEVICE_OUT_AUX_LINE;
 
     // TODO merge orientation and rotation
     private final boolean mMonitorOrientation;
@@ -491,8 +526,16 @@
         mContext = context;
         mContentResolver = context.getContentResolver();
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
-        mVoiceCapable = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
+
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable)) {
+            mPlatformType = PLATFORM_VOICE;
+        } else if (context.getPackageManager().hasSystemFeature(
+                                                            PackageManager.FEATURE_TELEVISION)) {
+            mPlatformType = PLATFORM_TELEVISION;
+        } else {
+            mPlatformType = PLATFORM_DEFAULT;
+        }
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
@@ -622,10 +665,15 @@
                                     BluetoothProfile.A2DP);
         }
 
-        HdmiControlManager hdmiManager =
+        mHdmiManager =
                 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
-        // Null if device is not Tv.
-        mHdmiTvClient = hdmiManager.getTvClient();
+        if (mHdmiManager != null) {
+            synchronized (mHdmiManager) {
+                mHdmiTvClient = mHdmiManager.getTvClient();
+                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
+                mHdmiCecSink = false;
+            }
+        }
 
         sendMsg(mAudioHandler,
                 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
@@ -670,6 +718,14 @@
         }
     }
 
+    private void checkAllFixedVolumeDevices()
+    {
+        int numStreamTypes = AudioSystem.getNumStreamTypes();
+        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+            mStreamStates[streamType].checkFixedVolumeDevices();
+        }
+    }
+
     private void createStreamStates() {
         int numStreamTypes = AudioSystem.getNumStreamTypes();
         VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
@@ -678,6 +734,7 @@
             streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
         }
 
+        checkAllFixedVolumeDevices();
         checkAllAliasStreamVolumes();
     }
 
@@ -702,19 +759,32 @@
 
     private void updateStreamVolumeAlias(boolean updateVolumes) {
         int dtmfStreamAlias;
-        if (mVoiceCapable) {
-            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
+
+        switch (mPlatformType) {
+        case PLATFORM_VOICE:
+            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
             dtmfStreamAlias = AudioSystem.STREAM_RING;
-        } else {
-            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
+            break;
+        case PLATFORM_TELEVISION:
+            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
+            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
+            break;
+        default:
+            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
             dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
         }
-        if (isInCommunication()) {
-            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
-            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
+
+        if (isPlatformTelevision()) {
+            mRingerModeAffectedStreams = 0;
         } else {
-            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
+            if (isInCommunication()) {
+                dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
+                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
+            } else {
+                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
+            }
         }
+
         mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
         if (updateVolumes) {
             mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
@@ -768,7 +838,7 @@
         if (ringerMode != ringerModeFromSettings) {
             Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
         }
-        if (mUseFixedVolume) {
+        if (mUseFixedVolume || isPlatformTelevision()) {
             ringerMode = AudioManager.RINGER_MODE_NORMAL;
         }
         synchronized(mSettingsLock) {
@@ -815,9 +885,6 @@
         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
 
-        // Restore the default media button receiver from the system settings
-        mMediaFocusControl.restoreMediaButtonReceiver();
-
         // Load settings for the volume controller
         mVolumeController.loadSettings(cr);
     }
@@ -1001,15 +1068,30 @@
 
             // Check if volume update should be send to Hdmi system audio.
             int newIndex = mStreamStates[streamType].getIndex(device);
-            if (mHdmiTvClient != null &&
-                streamTypeAlias == AudioSystem.STREAM_MUSIC &&
-                (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
-                oldIndex != newIndex) {
-                int maxIndex = getStreamMaxVolume(streamType);
-                synchronized (mHdmiTvClient) {
-                    if (mHdmiSystemAudioSupported) {
-                        mHdmiTvClient.setSystemAudioVolume(
-                                (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
+            if (mHdmiManager != null) {
+                synchronized (mHdmiManager) {
+                    if (mHdmiTvClient != null &&
+                        streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                        (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
+                        oldIndex != newIndex) {
+                        int maxIndex = getStreamMaxVolume(streamType);
+                        synchronized (mHdmiTvClient) {
+                            if (mHdmiSystemAudioSupported) {
+                                mHdmiTvClient.setSystemAudioVolume(
+                                        (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
+                            }
+                        }
+                    }
+                    // mHdmiCecSink true => mHdmiPlaybackClient != null
+                    if (mHdmiCecSink &&
+                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                            oldIndex != newIndex) {
+                        synchronized (mHdmiPlaybackClient) {
+                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
+                                                               KeyEvent.KEYCODE_VOLUME_UP;
+                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
+                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
+                        }
                     }
                 }
             }
@@ -1051,6 +1133,13 @@
             mFlags = flags;
             mDevice = device;
         }
+
+        @Override
+        public String toString() {
+            return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
+                    .append(mIndex).append(",flags=").append(mFlags).append(",device=")
+                    .append(mDevice).append('}').toString();
+        }
     };
 
     private void onSetStreamVolume(int streamType, int index, int flags, int device) {
@@ -1113,15 +1202,19 @@
                 }
             }
 
-            if (mHdmiTvClient != null &&
-                streamTypeAlias == AudioSystem.STREAM_MUSIC &&
-                (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
-                oldIndex != index) {
-                int maxIndex = getStreamMaxVolume(streamType);
-                synchronized (mHdmiTvClient) {
-                    if (mHdmiSystemAudioSupported) {
-                        mHdmiTvClient.setSystemAudioVolume(
-                                (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
+            if (mHdmiManager != null) {
+                synchronized (mHdmiManager) {
+                    if (mHdmiTvClient != null &&
+                        streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                        (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
+                        oldIndex != index) {
+                        int maxIndex = getStreamMaxVolume(streamType);
+                        synchronized (mHdmiTvClient) {
+                            if (mHdmiSystemAudioSupported) {
+                                mHdmiTvClient.setSystemAudioVolume(
+                                        (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
+                            }
+                        }
                     }
                 }
             }
@@ -1260,7 +1353,7 @@
 
     // UI update and Broadcast Intent
     private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
-        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
+        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
             streamType = AudioSystem.STREAM_NOTIFICATION;
         }
 
@@ -1349,10 +1442,14 @@
         }
 
         if (isStreamAffectedByMute(streamType)) {
-            if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
-                synchronized (mHdmiTvClient) {
-                    if (mHdmiSystemAudioSupported) {
-                        mHdmiTvClient.setSystemAudioMute(state);
+            if (mHdmiManager != null) {
+                synchronized (mHdmiManager) {
+                    if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
+                        synchronized (mHdmiTvClient) {
+                            if (mHdmiSystemAudioSupported) {
+                                mHdmiTvClient.setSystemAudioMute(state);
+                            }
+                        }
                     }
                 }
             }
@@ -1475,11 +1572,15 @@
 
     /** @see AudioManager#getMasterStreamType()  */
     public int getMasterStreamType() {
-        if (mVoiceCapable) {
-            return AudioSystem.STREAM_RING;
-        } else {
-            return AudioSystem.STREAM_NOTIFICATION;
+        switch (mPlatformType) {
+            case PLATFORM_VOICE:
+                return AudioSystem.STREAM_RING;
+            case PLATFORM_TELEVISION:
+                return AudioSystem.STREAM_MUSIC;
+            default:
+                break;
         }
+        return AudioSystem.STREAM_NOTIFICATION;
     }
 
     /** @see AudioManager#setMicrophoneMute(boolean) */
@@ -1507,7 +1608,7 @@
 
     /** @see AudioManager#setRingerMode(int) */
     public void setRingerMode(int ringerMode) {
-        if (mUseFixedVolume) {
+        if (mUseFixedVolume || isPlatformTelevision()) {
             return;
         }
 
@@ -1537,7 +1638,7 @@
                     ringerMode == AudioManager.RINGER_MODE_NORMAL) {
                     // ring and notifications volume should never be 0 when not silenced
                     // on voice capable devices
-                    if (mVoiceCapable &&
+                    if (isPlatformVoice() &&
                             mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
                         synchronized (mStreamStates[streamType]) {
                             Set set = mStreamStates[streamType].mIndex.entrySet();
@@ -2044,9 +2145,13 @@
         // muted by ringer mode have the correct volume
         setRingerModeInt(getRingerMode(), false);
 
+        checkAllFixedVolumeDevices();
         checkAllAliasStreamVolumes();
 
         synchronized (mSafeMediaVolumeState) {
+            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
+                    Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
+                    0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
                 enforceSafeMediaVolume();
             }
@@ -2619,20 +2724,27 @@
                             setSafeMediaVolumeEnabled(true);
                             mMusicActiveMs = 0;
                         }
+                        saveMusicActiveMs();
                     }
                 }
             }
         }
     }
 
+    private void saveMusicActiveMs() {
+        mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
+    }
+
     private void onConfigureSafeVolume(boolean force) {
         synchronized (mSafeMediaVolumeState) {
             int mcc = mContext.getResources().getConfiguration().mcc;
             if ((mMcc != mcc) || ((mMcc == 0) && force)) {
                 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
                         com.android.internal.R.integer.config_safe_media_volume_index) * 10;
-                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
-                        com.android.internal.R.bool.config_safe_media_volume_enabled);
+                boolean safeMediaVolumeEnabled =
+                        SystemProperties.getBoolean("audio.safemedia.force", false)
+                        || mContext.getResources().getBoolean(
+                                com.android.internal.R.bool.config_safe_media_volume_enabled);
 
                 // The persisted state is either "disabled" or "active": this is the state applied
                 // next time we boot and cannot be "inactive"
@@ -2643,8 +2755,13 @@
                     // the 30 seconds timeout for forced configuration. In this case we don't reset
                     // it to "active".
                     if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
-                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
-                        enforceSafeMediaVolume();
+                        if (mMusicActiveMs == 0) {
+                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+                            enforceSafeMediaVolume();
+                        } else {
+                            // We have existing playback time recorded, already confirmed.
+                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
+                        }
                     }
                 } else {
                     persistedState = SAFE_MEDIA_VOLUME_DISABLED;
@@ -2763,11 +2880,18 @@
                                         (1 << AudioSystem.STREAM_NOTIFICATION)|
                                         (1 << AudioSystem.STREAM_SYSTEM);
 
-        if (mVoiceCapable) {
-            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
-        } else {
-            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
+        switch (mPlatformType) {
+            case PLATFORM_VOICE:
+                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
+                break;
+            case PLATFORM_TELEVISION:
+                ringerModeAffectedStreams = 0;
+                break;
+            default:
+                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
+                break;
         }
+
         synchronized (mCameraSoundForced) {
             if (mCameraSoundForced) {
                 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
@@ -2836,7 +2960,8 @@
     }
 
     private int getActiveStreamType(int suggestedStreamType) {
-        if (mVoiceCapable) {
+        switch (mPlatformType) {
+        case PLATFORM_VOICE:
             if (isInCommunication()) {
                 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                         == AudioSystem.FORCE_BT_SCO) {
@@ -2866,12 +2991,26 @@
                 if (DEBUG_VOL)
                     Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
                 return AudioSystem.STREAM_MUSIC;
-            } else {
-                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
-                        + suggestedStreamType);
-                return suggestedStreamType;
             }
-        } else {
+            break;
+        case PLATFORM_TELEVISION:
+            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
+                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
+                    return AudioSystem.STREAM_MUSIC;
+                } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(
+                                                                        AudioSystem.STREAM_MUSIC)) {
+                    if (DEBUG_VOL)
+                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
+                    return STREAM_REMOTE_MUSIC;
+                } else {
+                    if (DEBUG_VOL) Log.v(TAG,
+                            "getActiveStreamType: using STREAM_MUSIC as default");
+                    return AudioSystem.STREAM_MUSIC;
+                }
+            }
+            break;
+        default:
             if (isInCommunication()) {
                 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                         == AudioSystem.FORCE_BT_SCO) {
@@ -2902,12 +3041,12 @@
                             "getActiveStreamType: using STREAM_NOTIFICATION as default");
                     return AudioSystem.STREAM_NOTIFICATION;
                 }
-            } else {
-                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
-                        + suggestedStreamType);
-                return suggestedStreamType;
             }
+            break;
         }
+        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
+                + suggestedStreamType);
+        return suggestedStreamType;
     }
 
     private void broadcastRingerMode(int ringerMode) {
@@ -3101,13 +3240,7 @@
                         continue;
                     }
 
-                    // ignore settings for fixed volume devices: volume should always be at max or 0
-                    if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
-                            ((device & mFixedVolumeDevices) != 0)) {
-                        mIndex.put(device, (index != 0) ? mIndexMax : 0);
-                    } else {
-                        mIndex.put(device, getValidIndex(10 * index));
-                    }
+                    mIndex.put(device, getValidIndex(10 * index));
                 }
             }
         }
@@ -3266,6 +3399,25 @@
             return mStreamType;
         }
 
+        public void checkFixedVolumeDevices() {
+            synchronized (VolumeStreamState.class) {
+                // ignore settings for fixed volume devices: volume should always be at max or 0
+                if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
+                    Set set = mIndex.entrySet();
+                    Iterator i = set.iterator();
+                    while (i.hasNext()) {
+                        Map.Entry entry = (Map.Entry)i.next();
+                        int device = ((Integer)entry.getKey()).intValue();
+                        int index = ((Integer)entry.getValue()).intValue();
+                        if (((device & mFixedVolumeDevices) != 0) && index != 0) {
+                            entry.setValue(mIndexMax);
+                        }
+                        applyDeviceVolume(device);
+                    }
+                }
+            }
+        }
+
         private int getValidIndex(int index) {
             if (index < 0) {
                 return 0;
@@ -3472,6 +3624,9 @@
             if (mUseFixedVolume) {
                 return;
             }
+            if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
+                return;
+            }
             System.putIntForUser(mContentResolver,
                       streamState.getSettingNameForDevice(device),
                       (streamState.getIndex(device) + 5)/ 10,
@@ -3828,11 +3983,13 @@
                                 mDockAudioMediaEnabled ?
                                         AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
                     }
-
-                    if (mHdmiTvClient != null) {
-                        setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
+                    if (mHdmiManager != null) {
+                        synchronized (mHdmiManager) {
+                            if (mHdmiTvClient != null) {
+                                setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
+                            }
+                        }
                     }
-
                     // indicate the end of reconfiguration phase to audio HAL
                     AudioSystem.setParameters("restarting=false");
                     break;
@@ -3932,6 +4089,13 @@
                 case MSG_SYSTEM_READY:
                     onSystemReady();
                     break;
+
+                case MSG_PERSIST_MUSIC_ACTIVE_MS:
+                    final int musicActiveMs = msg.arg1;
+                    Settings.Secure.putIntForUser(mContentResolver,
+                            Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
+                            UserHandle.USER_CURRENT);
+                    break;
             }
         }
     }
@@ -4278,6 +4442,27 @@
                             null,
                             MUSIC_ACTIVE_POLL_PERIOD_MS);
                 }
+                // Television devices without CEC service apply software volume on HDMI output
+                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
+                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+                    checkAllFixedVolumeDevices();
+                    if (mHdmiManager != null) {
+                        synchronized (mHdmiManager) {
+                            if (mHdmiPlaybackClient != null) {
+                                mHdmiCecSink = false;
+                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
+                            }
+                        }
+                    }
+                }
+            } else {
+                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
+                    if (mHdmiManager != null) {
+                        synchronized (mHdmiManager) {
+                            mHdmiCecSink = false;
+                        }
+                    }
+                }
             }
             if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
                 sendDeviceConnectionIntent(device, state, name);
@@ -4580,18 +4765,20 @@
                     if (cameraSoundForced != mCameraSoundForced) {
                         mCameraSoundForced = cameraSoundForced;
 
-                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
-                        if (cameraSoundForced) {
-                            s.setAllIndexesToMax();
-                            mRingerModeAffectedStreams &=
-                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
-                        } else {
-                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
-                            mRingerModeAffectedStreams |=
-                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+                        if (!isPlatformTelevision()) {
+                            VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
+                            if (cameraSoundForced) {
+                                s.setAllIndexesToMax();
+                                mRingerModeAffectedStreams &=
+                                        ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+                            } else {
+                                s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
+                                mRingerModeAffectedStreams |=
+                                        (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+                            }
+                            // take new state into account for streams muted by ringer mode
+                            setRingerModeInt(getRingerMode(), false);
                         }
-                        // take new state into account for streams muted by ringer mode
-                        setRingerModeInt(getRingerMode(), false);
 
                         sendMsg(mAudioHandler,
                                 MSG_SET_FORCE_USE,
@@ -4707,10 +4894,10 @@
     // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
     // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
     // (when user opts out).
-    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
-    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
-    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
-    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
+    private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
+    private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
+    private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
+    private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
     private Integer mSafeMediaVolumeState;
 
     private int mMcc = 0;
@@ -4736,7 +4923,8 @@
                     enforceSafeMediaVolume();
                 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
                     mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
-                    mMusicActiveMs = 0;
+                    mMusicActiveMs = 1;  // nonzero = confirmed
+                    saveMusicActiveMs();
                     sendMsg(mAudioHandler,
                             MSG_CHECK_MUSIC_ACTIVE,
                             SENDMSG_REPLACE,
@@ -4807,27 +4995,57 @@
     // to HdmiControlService so that audio recevier can handle volume change.
     //==========================================================================================
 
+    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
+        public void onComplete(int status) {
+            if (mHdmiManager != null) {
+                synchronized (mHdmiManager) {
+                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
+                    // Television devices without CEC service apply software volume on HDMI output
+                    if (isPlatformTelevision() && !mHdmiCecSink) {
+                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
+                    }
+                    checkAllFixedVolumeDevices();
+                }
+            }
+        }
+    };
+
     // If HDMI-CEC system audio is supported
     private boolean mHdmiSystemAudioSupported = false;
     // Set only when device is tv.
     private HdmiTvClient mHdmiTvClient;
+    // true if the device has system feature PackageManager.FEATURE_TELEVISION.
+    // cached HdmiControlManager interface
+    private HdmiControlManager mHdmiManager;
+    // Set only when device is a set-top box.
+    private HdmiPlaybackClient mHdmiPlaybackClient;
+    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
+    private boolean mHdmiCecSink;
+
+    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
 
     @Override
     public int setHdmiSystemAudioSupported(boolean on) {
-        if (mHdmiTvClient == null) {
-            Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
-            return AudioSystem.DEVICE_NONE;
-        }
+        int device = AudioSystem.DEVICE_NONE;
+        if (mHdmiManager != null) {
+            synchronized (mHdmiManager) {
+                if (mHdmiTvClient == null) {
+                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
+                    return device;
+                }
 
-        synchronized (mHdmiTvClient) {
-            if (mHdmiSystemAudioSupported == on) {
-                return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
+                synchronized (mHdmiTvClient) {
+                    if (mHdmiSystemAudioSupported != on) {
+                        mHdmiSystemAudioSupported = on;
+                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
+                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
+                                     AudioSystem.FORCE_NONE);
+                    }
+                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
+                }
             }
-            mHdmiSystemAudioSupported = on;
-            AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
-                    on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE);
         }
-        return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
+        return device;
     }
 
     //==========================================================================================
@@ -4872,7 +5090,25 @@
         pw.println("\nAudio routes:");
         pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
         pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
+
+        pw.println("\nOther state:");
         pw.print("  mVolumeController="); pw.println(mVolumeController);
+        pw.print("  mSafeMediaVolumeState=");
+        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
+        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
+        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
+        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
+        pw.print("  mMcc="); pw.println(mMcc);
+    }
+
+    private static String safeMediaVolumeStateToString(Integer state) {
+        switch(state) {
+            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
+            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
+            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
+            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
+        }
+        return null;
     }
 
     // Inform AudioFlinger of our device's low RAM attribute
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index f9e49c1..8883d28 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -149,6 +149,39 @@
     private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2160P;
 
     /**
+     * High speed ( >= 100fps) quality level corresponding to the lowest available resolution.
+     */
+    public static final int QUALITY_HIGH_SPEED_LOW = 2000;
+
+    /**
+     * High speed ( >= 100fps) quality level corresponding to the highest available resolution.
+     */
+    public static final int QUALITY_HIGH_SPEED_HIGH = 2001;
+
+    /**
+     * High speed ( >= 100fps) quality level corresponding to the 480p (720 x 480) resolution.
+     *
+     * Note that the horizontal resolution for 480p can also be other
+     * values, such as 640 or 704, instead of 720.
+     */
+    public static final int QUALITY_HIGH_SPEED_480P = 2002;
+
+    /**
+     * High speed ( >= 100fps) quality level corresponding to the 720p (1280 x 720) resolution.
+     */
+    public static final int QUALITY_HIGH_SPEED_720P = 2003;
+
+    /**
+     * High speed ( >= 100fps) quality level corresponding to the 1080p (1920 x 1080 or 1920x1088)
+     * resolution.
+     */
+    public static final int QUALITY_HIGH_SPEED_1080P = 2004;
+
+    // Start and end of high speed quality list
+    private static final int QUALITY_HIGH_SPEED_LIST_START = QUALITY_HIGH_SPEED_LOW;
+    private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_1080P;
+
+    /**
      * Default recording duration in seconds before the session is terminated.
      * This is useful for applications like MMS has limited file size requirement.
      */
@@ -240,13 +273,17 @@
      * {@link #hasProfile(int, int)}.
      * QUALITY_LOW refers to the lowest quality available, while QUALITY_HIGH refers to
      * the highest quality available.
-     * QUALITY_LOW/QUALITY_HIGH have to match one of qcif, cif, 480p, 720p, or 1080p.
-     * E.g. if the device supports 480p, 720p, and 1080p, then low is 480p and high is
-     * 1080p.
+     * QUALITY_LOW/QUALITY_HIGH have to match one of qcif, cif, 480p, 720p, 1080p or 2160p.
+     * E.g. if the device supports 480p, 720p, 1080p and 2160p, then low is 480p and high is
+     * 2160p.
      *
      * The same is true for time lapse quality levels, i.e. QUALITY_TIME_LAPSE_LOW,
      * QUALITY_TIME_LAPSE_HIGH are guaranteed to be supported and have to match one of
-     * qcif, cif, 480p, 720p, or 1080p.
+     * qcif, cif, 480p, 720p, 1080p, or 2160p.
+     *
+     * For high speed quality levels, they may or may not be supported. If a subset of the levels
+     * are supported, QUALITY_HIGH_SPEED_LOW and QUALITY_HIGH_SPEED_HIGH are guaranteed to be
+     * supported and have to match one of 480p, 720p, or 1080p.
      *
      * A camcorder recording session with higher quality level usually has higher output
      * bit rate, better video and/or audio recording quality, larger video frame
@@ -262,6 +299,7 @@
      * @see #QUALITY_480P
      * @see #QUALITY_720P
      * @see #QUALITY_1080P
+     * @see #QUALITY_2160P
      * @see #QUALITY_TIME_LAPSE_LOW
      * @see #QUALITY_TIME_LAPSE_HIGH
      * @see #QUALITY_TIME_LAPSE_QCIF
@@ -269,12 +307,20 @@
      * @see #QUALITY_TIME_LAPSE_480P
      * @see #QUALITY_TIME_LAPSE_720P
      * @see #QUALITY_TIME_LAPSE_1080P
-     */
+     * @see #QUALITY_TIME_LAPSE_2160P
+     * @see #QUALITY_HIGH_SPEED_LOW
+     * @see #QUALITY_HIGH_SPEED_HIGH
+     * @see #QUALITY_HIGH_SPEED_480P
+     * @see #QUALITY_HIGH_SPEED_720P
+     * @see #QUALITY_HIGH_SPEED_1080P
+    */
     public static CamcorderProfile get(int cameraId, int quality) {
         if (!((quality >= QUALITY_LIST_START &&
                quality <= QUALITY_LIST_END) ||
               (quality >= QUALITY_TIME_LAPSE_LIST_START &&
-               quality <= QUALITY_TIME_LAPSE_LIST_END))) {
+               quality <= QUALITY_TIME_LAPSE_LIST_END) ||
+               (quality >= QUALITY_HIGH_SPEED_LIST_START &&
+               quality <= QUALITY_HIGH_SPEED_LIST_END))) {
             String errMessage = "Unsupported quality level: " + quality;
             throw new IllegalArgumentException(errMessage);
         }
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index f84c383..275d9b2 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,7 +16,10 @@
 
 package android.media;
 
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
 import android.media.Image;
+import android.media.Image.Plane;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
 import android.media.MediaCrypto;
@@ -29,6 +32,7 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
 import java.util.Arrays;
 import java.util.Map;
 
@@ -1537,4 +1541,175 @@
     }
 
     private long mNativeContext;
+
+    /** @hide */
+    public static class MediaImage extends Image {
+        private final boolean mIsReadOnly;
+        private boolean mIsValid;
+        private final int mWidth;
+        private final int mHeight;
+        private final int mFormat;
+        private long mTimestamp;
+        private final Plane[] mPlanes;
+        private final ByteBuffer mBuffer;
+        private final ByteBuffer mInfo;
+        private final int mXOffset;
+        private final int mYOffset;
+
+        private final static int TYPE_YUV = 1;
+
+        public int getFormat() {
+            checkValid();
+            return mFormat;
+        }
+
+        public int getHeight() {
+            checkValid();
+            return mHeight;
+        }
+
+        public int getWidth() {
+            checkValid();
+            return mWidth;
+        }
+
+        public long getTimestamp() {
+            checkValid();
+            return mTimestamp;
+        }
+
+        public Plane[] getPlanes() {
+            checkValid();
+            return Arrays.copyOf(mPlanes, mPlanes.length);
+        }
+
+        public void close() {
+            if (mIsValid) {
+                java.nio.NioUtils.freeDirectBuffer(mBuffer);
+                mIsValid = false;
+            }
+        }
+
+        /**
+         * Set the crop rectangle associated with this frame.
+         * <p>
+         * The crop rectangle specifies the region of valid pixels in the image,
+         * using coordinates in the largest-resolution plane.
+         */
+        public void setCropRect(Rect cropRect) {
+            if (mIsReadOnly) {
+                throw new ReadOnlyBufferException();
+            }
+            super.setCropRect(cropRect);
+        }
+
+        private void checkValid() {
+            if (!mIsValid) {
+                throw new IllegalStateException("Image is already released");
+            }
+        }
+
+        private int readInt(ByteBuffer buffer, boolean asLong) {
+            if (asLong) {
+                return (int)buffer.getLong();
+            } else {
+                return buffer.getInt();
+            }
+        }
+
+        public MediaImage(
+                ByteBuffer buffer, ByteBuffer info, boolean readOnly,
+                long timestamp, int xOffset, int yOffset, Rect cropRect) {
+            mFormat = ImageFormat.YUV_420_888;
+            mTimestamp = timestamp;
+            mIsValid = true;
+            mIsReadOnly = buffer.isReadOnly();
+            mBuffer = buffer.duplicate();
+            if (cropRect != null) {
+                cropRect.offset(-xOffset, -yOffset);
+            }
+            mCropRect = cropRect;
+
+            // save offsets and info
+            mXOffset = xOffset;
+            mYOffset = yOffset;
+            mInfo = info;
+
+            // read media-info.  the size of media info can be 80 or 156 depending on
+            // whether it was created on a 32- or 64-bit process.  See MediaImage
+            if (info.remaining() == 80 || info.remaining() == 156) {
+                boolean sizeIsLong = info.remaining() == 156;
+                int type = info.getInt();
+                if (type != TYPE_YUV) {
+                    throw new UnsupportedOperationException("unsupported type: " + type);
+                }
+                int numPlanes = readInt(info, sizeIsLong);
+                if (numPlanes != 3) {
+                    throw new RuntimeException("unexpected number of planes: " + numPlanes);
+                }
+                mWidth = readInt(info, sizeIsLong);
+                mHeight = readInt(info, sizeIsLong);
+                if (mWidth < 1 || mHeight < 1) {
+                    throw new UnsupportedOperationException(
+                            "unsupported size: " + mWidth + "x" + mHeight);
+                }
+                int bitDepth = readInt(info, sizeIsLong);
+                if (bitDepth != 8) {
+                    throw new UnsupportedOperationException("unsupported bit depth: " + bitDepth);
+                }
+                mPlanes = new MediaPlane[numPlanes];
+                for (int ix = 0; ix < numPlanes; ix++) {
+                    int planeOffset = readInt(info, sizeIsLong);
+                    int colInc = readInt(info, sizeIsLong);
+                    int rowInc = readInt(info, sizeIsLong);
+                    int horiz = readInt(info, sizeIsLong);
+                    int vert = readInt(info, sizeIsLong);
+                    if (horiz != vert || horiz != (ix == 0 ? 1 : 2)) {
+                        throw new UnsupportedOperationException("unexpected subsampling: "
+                                + horiz + "x" + vert + " on plane " + ix);
+                    }
+
+                    buffer.clear();
+                    buffer.position(mBuffer.position() + planeOffset
+                            + (xOffset / horiz) * colInc + (yOffset / vert) * rowInc);
+                    buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8)
+                            + (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc);
+                    mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc);
+                }
+            } else {
+                throw new UnsupportedOperationException(
+                        "unsupported info length: " + info.remaining());
+            }
+        }
+
+        private class MediaPlane extends Plane {
+            public MediaPlane(ByteBuffer buffer, int rowInc, int colInc) {
+                mData = buffer;
+                mRowInc = rowInc;
+                mColInc = colInc;
+            }
+
+            @Override
+            public int getRowStride() {
+                checkValid();
+                return mRowInc;
+            }
+
+            @Override
+            public int getPixelStride() {
+                checkValid();
+                return mColInc;
+            }
+
+            @Override
+            public ByteBuffer getBuffer() {
+                checkValid();
+                return mData;
+            }
+
+            private final int mRowInc;
+            private final int mColInc;
+            private final ByteBuffer mData;
+        }
+    }
 }
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 6004ecf..c67e397 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -78,7 +78,6 @@
     private final Context mContext;
     private final ContentResolver mContentResolver;
     private final AudioService.VolumeController mVolumeController;
-    private final BroadcastReceiver mReceiver = new PackageIntentsReceiver();
     private final AppOpsManager mAppOps;
     private final KeyguardManager mKeyguardManager;
     private final AudioService mAudioService;
@@ -103,16 +102,6 @@
                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
         tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
 
-        // Register for package addition/removal/change intent broadcasts
-        //    for media button receiver persistence
-        IntentFilter pkgFilter = new IntentFilter();
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
-        pkgFilter.addDataScheme("package");
-        mContext.registerReceiver(mReceiver, pkgFilter);
-
         mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
         mKeyguardManager =
                 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
@@ -321,7 +310,6 @@
     //==========================================================================================
 
     // event handler messages
-    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 0;
     private static final int MSG_RCDISPLAY_CLEAR = 1;
     private static final int MSG_RCDISPLAY_UPDATE = 2;
     private static final int MSG_REEVALUATE_REMOTE = 3;
@@ -362,10 +350,6 @@
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
-                case MSG_PERSIST_MEDIABUTTONRECEIVER:
-                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
-                    break;
-
                 case MSG_RCDISPLAY_CLEAR:
                     onRcDisplayClear();
                     break;
@@ -874,29 +858,6 @@
 
     }
 
-    private class PackageIntentsReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
-                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
-                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
-                    // a package is being removed, not replaced
-                    String packageName = intent.getData().getSchemeSpecificPart();
-                    if (packageName != null) {
-                        cleanupMediaButtonReceiverForPackage(packageName, true);
-                    }
-                }
-            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
-                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
-                String packageName = intent.getData().getSchemeSpecificPart();
-                if (packageName != null) {
-                    cleanupMediaButtonReceiverForPackage(packageName, false);
-                }
-            }
-        }
-    }
-
     private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
         if (keyEvent == null) {
             return false;
@@ -1113,85 +1074,6 @@
 
     /**
      * Helper function:
-     * Remove any entry in the remote control stack that has the same package name as packageName
-     * Pre-condition: packageName != null
-     */
-    private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
-        synchronized(mPRStack) {
-            if (mPRStack.empty()) {
-                return;
-            } else {
-                final PackageManager pm = mContext.getPackageManager();
-                PlayerRecord oldTop = mPRStack.peek();
-                Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-                // iterate over the stack entries
-                // (using an iterator on the stack so we can safely remove an entry after having
-                //  evaluated it, traversal order doesn't matter here)
-                while(stackIterator.hasNext()) {
-                    PlayerRecord prse = stackIterator.next();
-                    if (removeAll
-                            && packageName.equals(prse.getMediaButtonIntent().getCreatorPackage()))
-                    {
-                        // a stack entry is from the package being removed, remove it from the stack
-                        stackIterator.remove();
-                        prse.destroy();
-                    } else if (prse.getMediaButtonReceiver() != null) {
-                        try {
-                            // Check to see if this receiver still exists.
-                            pm.getReceiverInfo(prse.getMediaButtonReceiver(), 0);
-                        } catch (PackageManager.NameNotFoundException e) {
-                            // Not found -- remove it!
-                            stackIterator.remove();
-                            prse.destroy();
-                        }
-                    }
-                }
-                if (mPRStack.empty()) {
-                    // no saved media button receiver
-                    mEventHandler.sendMessage(
-                            mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
-                                    null));
-                } else if (oldTop != mPRStack.peek()) {
-                    // the top of the stack has changed, save it in the system settings
-                    // by posting a message to persist it; only do this however if it has
-                    // a concrete component name (is not a transient registration)
-                    PlayerRecord prse = mPRStack.peek();
-                    if (prse.getMediaButtonReceiver() != null) {
-                        mEventHandler.sendMessage(
-                                mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
-                                        prse.getMediaButtonReceiver()));
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Restore remote control receiver from the system settings.
-     */
-    protected void restoreMediaButtonReceiver() {
-        String receiverName = Settings.System.getStringForUser(mContentResolver,
-                Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
-        if ((null != receiverName) && !receiverName.isEmpty()) {
-            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
-            if (eventReceiver == null) {
-                // an invalid name was persisted
-                return;
-            }
-            // construct a PendingIntent targeted to the restored component name
-            // for the media button and register it
-            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-            //     the associated intent will be handled by the component being registered
-            mediaButtonIntent.setComponent(eventReceiver);
-            PendingIntent pi = PendingIntent.getBroadcast(mContext,
-                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
-            registerMediaButtonIntent(pi, eventReceiver, null /*token*/);
-        }
-    }
-
-    /**
-     * Helper function:
      * Push the new media button receiver "near" the top of the PlayerRecord stack.
      * "Near the top" is defined as:
      *   - at the top if the current PlayerRecord at the top is not playing
@@ -1258,13 +1140,6 @@
                 }
             }
 
-            topChanged = (oldTopPrse != mPRStack.lastElement());
-            // post message to persist the default media button receiver
-            if (topChanged && (target != null)) {
-                mEventHandler.sendMessage( mEventHandler.obtainMessage(
-                        MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
-            }
-
         } catch (ArrayIndexOutOfBoundsException e) {
             // not expected to happen, indicates improper concurrent modification or bad index
             Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex
@@ -1309,13 +1184,6 @@
         return false;
     }
 
-    private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
-        Settings.System.putStringForUser(mContentResolver,
-                                         Settings.System.MEDIA_BUTTON_RECEIVER,
-                                         receiver == null ? "" : receiver.flattenToString(),
-                                         UserHandle.USER_CURRENT);
-    }
-
     //==========================================================================================
     // Remote control display / client
     //==========================================================================================
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index a95348f..a1ccf60 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -43,7 +43,8 @@
  * <tr><td>{@link #KEY_COLOR_FORMAT}</td><td>Integer</td><td>set by the user
  *         for encoders, readable in the output format of decoders</b></td></tr>
  * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
- * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_CAPTURE_RATE}</td><td>Integer</td><td></td></tr>
+* <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
  * <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
  * <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
  * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr>
@@ -206,6 +207,21 @@
     public static final String KEY_FRAME_RATE = "frame-rate";
 
     /**
+     * A key describing the capture rate of a video format in frames/sec.
+     * <p>
+     * When capture rate is different than the frame rate, it means that the
+     * video is acquired at a different rate than the playback, which produces
+     * slow motion or timelapse effect during playback. Application can use the
+     * value of this key to tell the relative speed ratio between capture and
+     * playback rates when the video was recorded.
+     * </p>
+     * <p>
+     * The associated value is an integer or a float.
+     * </p>
+     */
+    public static final String KEY_CAPTURE_RATE = "capture-rate";
+
+    /**
      * A key describing the frequency of I frames expressed in secs
      * between I frames.
      * The associated value is an integer.
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 5d2f3bd..3f7ebce 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.format.Time;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -73,7 +74,8 @@
     public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
 
     /**
-     * The date the media was created or published as TODO determine format.
+     * The date the media was created or published. The format is unspecified
+     * but RFC 3339 is recommended.
      */
     public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
 
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 0235871..db6315a 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -18,28 +18,20 @@
 
 import android.app.PendingIntent;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
 import android.media.session.MediaSessionLegacyHelper;
 import android.media.session.PlaybackState;
 import android.media.session.MediaSession;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.util.Log;
 
 import java.lang.IllegalArgumentException;
-import java.util.ArrayList;
-import java.util.Iterator;
 
 /**
  * RemoteControlClient enables exposing information meant to be consumed by remote controls
@@ -754,7 +746,8 @@
             // USE_SESSIONS
             if (mSession != null) {
                 PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState);
-                bob.setActions(PlaybackState.getActionsFromRccControlFlags(transportControlFlags));
+                bob.setActions(
+                        PlaybackState.getActionsFromRccControlFlags(transportControlFlags));
                 mSessionPlaybackState = bob.build();
                 mSession.setPlaybackState(mSessionPlaybackState);
             }
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 966fbb0..0aaaf46 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -23,8 +23,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.media.IRemoteControlDisplay;
-import android.media.MediaMetadataEditor;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionLegacyHelper;
@@ -76,8 +74,7 @@
     private MetadataEditor mMetadataEditor;
 
     private MediaSessionManager mSessionManager;
-    private MediaSessionManager.SessionListener mSessionListener
-            = new TopTransportSessionListener();
+    private MediaSessionManager.SessionListener mSessionListener;
     private MediaController.Callback mSessionCb = new MediaControllerCallback();
 
     /**
@@ -143,6 +140,7 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mSessionManager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
+        mSessionListener = new TopTransportSessionListener(context);
 
         if (ActivityManager.isLowRamDeviceStatic()) {
             mMaxBitmapDimension = MAX_BITMAP_DIMENSION;
@@ -216,7 +214,7 @@
     public String getRemoteControlClientPackageName() {
         if (USE_SESSIONS) {
             synchronized (mInfoLock) {
-                return mCurrentSession != null ? mCurrentSession.getSessionInfo().getPackageName()
+                return mCurrentSession != null ? mCurrentSession.getPackageName()
                         : null;
             }
         } else {
@@ -397,12 +395,6 @@
                 mArtworkWidth = -1;
                 mArtworkHeight = -1;
             }
-            if (mIsRegistered) {
-                mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd,
-                        mArtworkWidth, mArtworkHeight);
-            } // else new values have been stored, and will be read by AudioManager with
-              //    RemoteController.getArtworkSize() when AudioManager.registerRemoteController()
-              //    is called.
         }
         return true;
     }
@@ -719,6 +711,11 @@
      * currently tracked session if it has changed.
      */
     private class TopTransportSessionListener extends MediaSessionManager.SessionListener {
+
+        public TopTransportSessionListener(Context context) {
+            super(context);
+        }
+
         @Override
         public void onActiveSessionsChanged(List<MediaController> controllers) {
             int size = controllers.size();
@@ -988,8 +985,8 @@
                             0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */);
                 }
             } else if (mCurrentSession == null
-                    || !controller.getSessionInfo().getId()
-                            .equals(mCurrentSession.getSessionInfo().getId())) {
+                    || !controller.getSessionToken()
+                            .equals(mCurrentSession.getSessionToken())) {
                 if (mCurrentSession != null) {
                     mCurrentSession.removeCallback(mSessionCb);
                 }
@@ -1025,8 +1022,8 @@
                         state.getPosition(), state.getPlaybackSpeed());
             }
             if (state != null) {
-                l.onClientTransportControlUpdate(PlaybackState.getRccControlFlagsFromActions(state
-                        .getActions()));
+                l.onClientTransportControlUpdate(
+                        PlaybackState.getRccControlFlagsFromActions(state.getActions()));
             }
         }
     }
@@ -1044,7 +1041,8 @@
             boolean canRate = mCurrentSession != null
                     && mCurrentSession.getRatingType() != Rating.RATING_NONE;
             long editableKeys = canRate ? MediaMetadataEditor.RATING_KEY_BY_USER : 0;
-            Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata);
+            Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata,
+                    mArtworkWidth, mArtworkHeight);
             mMetadataEditor = new MetadataEditor(legacyMetadata, editableKeys);
             metadataEditor = mMetadataEditor;
         }
diff --git a/media/java/android/media/browse/IMediaBrowserService.aidl b/media/java/android/media/browse/IMediaBrowserService.aidl
index 177bd1b..8acd724 100644
--- a/media/java/android/media/browse/IMediaBrowserService.aidl
+++ b/media/java/android/media/browse/IMediaBrowserService.aidl
@@ -18,5 +18,6 @@
 
     void addSubscription(in Uri uri, IMediaBrowserServiceCallbacks callbacks);
     void removeSubscription(in Uri uri, IMediaBrowserServiceCallbacks callbacks);
-    void loadThumbnail(in Uri uri, int width, int height, IMediaBrowserServiceCallbacks callbacks);
+    void loadIcon(in int seqNum, in Uri uri, int width, int height,
+            IMediaBrowserServiceCallbacks callbacks);
 }
\ No newline at end of file
diff --git a/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl b/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl
index 1f03a1a..06fabcc 100644
--- a/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl
+++ b/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl
@@ -24,5 +24,5 @@
     void onConnect(in Uri root, in MediaSession.Token session, in Bundle extras);
     void onConnectFailed();
     void onLoadChildren(in Uri uri, in ParceledListSlice list);
-    void onLoadThumbnail(in Uri uri, int width, int height, in Bitmap bitmap);
+    void onLoadIcon(int seqNum, in Bitmap bitmap);
 }
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index d17f95d..858383e 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -33,6 +33,7 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -40,6 +41,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -65,8 +67,8 @@
     private final Handler mHandler = new Handler();
     private final ArrayMap<Uri,Subscription> mSubscriptions =
             new ArrayMap<Uri, MediaBrowser.Subscription>();
-    private final ArrayMap<ThumbnailRequest, HashSet<ThumbnailCallback>> mThumbnailCallbacks =
-            new ArrayMap<ThumbnailRequest, HashSet<ThumbnailCallback>>();
+    private final SparseArray<IconRequest> mIconRequests =
+            new SparseArray<IconRequest>();
 
     private int mState = CONNECT_STATE_DISCONNECTED;
     private MediaServiceConnection mServiceConnection;
@@ -75,6 +77,7 @@
     private Uri mRootUri;
     private MediaSession.Token mMediaSessionToken;
     private Bundle mExtras;
+    private int mNextSeq;
 
     /**
      * Creates a media browser for the specified media browse service.
@@ -349,43 +352,42 @@
     }
 
     /**
-     * Loads the thumbnail of a media item.
+     * Loads the icon of a media item.
      *
-     * @param uri The uri of the thumbnail.
+     * @param uri The uri of the Icon.
      * @param width The preferred width of the icon in dp.
      * @param height The preferred width of the icon in dp.
-     * @param callback The callback to receive the thumbnail.
+     * @param callback The callback to receive the icon.
      */
-    public void loadThumbnail(final @NonNull Uri uri, final int width, final int height,
-            final @NonNull ThumbnailCallback callback) {
+    public void loadIcon(final @NonNull Uri uri, final int width, final int height,
+            final @NonNull IconCallback callback) {
         if (uri == null) {
-            throw new IllegalArgumentException("thumbnail uri cannot be null");
+            throw new IllegalArgumentException("Icon uri cannot be null");
         }
         if (callback == null) {
-            throw new IllegalArgumentException("thumbnail callback cannot be null");
+            throw new IllegalArgumentException("Icon callback cannot be null");
         }
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                HashSet<ThumbnailCallback> callbackSet;
-                ThumbnailRequest request = new ThumbnailRequest(uri, width, height);
-                callbackSet = mThumbnailCallbacks.get(request);
-                if (callbackSet != null) {
-                    callbackSet.add(callback);
-                    mThumbnailCallbacks.put(request, callbackSet);
-                    // same request has been sent. we will wait for the callback.
-                    return;
+                for (int i = 0; i < mIconRequests.size(); i++) {
+                    IconRequest existingRequest = mIconRequests.valueAt(i);
+                    if (existingRequest.isSameRequest(uri, width, height)) {
+                        existingRequest.addCallback(callback);
+                        return;
+                    }
                 }
-                callbackSet = new HashSet<ThumbnailCallback>();
-                callbackSet.add(callback);
-                mThumbnailCallbacks.put(request, callbackSet);
+                final int seq = mNextSeq++;
+                IconRequest request = new IconRequest(seq, uri, width, height);
+                request.addCallback(callback);
+                mIconRequests.put(seq, request);
                 if (mState == CONNECT_STATE_CONNECTED) {
                     try {
-                        mServiceBinder.loadThumbnail(uri, width, height, mServiceCallbacks);
+                        mServiceBinder.loadIcon(seq, uri, width, height, mServiceCallbacks);
                     } catch (RemoteException e) {
                         // Process is crashing.  We will disconnect, and upon reconnect we will
-                        // automatically reload the thumbnails. So nothing to do here.
-                        Log.d(TAG, "loadThumbnail failed with RemoteException uri=" + uri);
+                        // automatically reload the icons. So nothing to do here.
+                        Log.d(TAG, "loadIcon failed with RemoteException uri=" + uri);
                     }
                 }
             }
@@ -449,17 +451,17 @@
                     }
                 }
 
-                for (ThumbnailRequest request : mThumbnailCallbacks.keySet()) {
+                for (int i = 0; i < mIconRequests.size(); i++) {
+                    IconRequest request = mIconRequests.valueAt(i);
                     try {
-                        mServiceBinder.loadThumbnail(request.uri, request.width, request.height,
-                                mServiceCallbacks);
+                        mServiceBinder.loadIcon(request.mSeq, request.mUri,
+                                request.mWidth, request.mHeight, mServiceCallbacks);
                     } catch (RemoteException e) {
                         // Process is crashing.  We will disconnect, and upon reconnect we will
                         // automatically reload. So nothing to do here.
-                        Log.d(TAG, "loadThumbnail failed with RemoteException uri=" + request.uri);
+                        Log.d(TAG, "loadIcon failed with RemoteException request=" + request);
                     }
                 }
-
             }
         });
     }
@@ -526,27 +528,27 @@
         });
     }
 
-    private final void onLoadThumbnail(final IMediaBrowserServiceCallbacks callback,
-            final ThumbnailRequest request, final Bitmap bitmap) {
+    private final void onLoadIcon(final IMediaBrowserServiceCallbacks callback,
+            final int seqNum, final Bitmap bitmap) {
         mHandler.post(new Runnable() {
             @Override
             public void run() {
                 // Check that there hasn't been a disconnect or a different
                 // ServiceConnection.
-                if (!isCurrent(callback, "onLoadThumbnail")) {
+                if (!isCurrent(callback, "onLoadIcon")) {
                     return;
                 }
 
-                Set<ThumbnailCallback> callbackSet = mThumbnailCallbacks.get(request);
-                if (callbackSet == null) {
-                    Log.d(TAG, "onLoadThumbnail called for request=" + request +
-                            " but the callback is not registered");
+                IconRequest request = mIconRequests.get(seqNum);
+                if (request == null) {
+                    Log.d(TAG, "onLoadIcon called for seqNum=" + seqNum + " request="
+                            + request + " but the request is not registered");
                     return;
                 }
-                for (ThumbnailCallback thumbnailCallback : callbackSet) {
-                    thumbnailCallback.onThumbnailLoaded(request.uri, bitmap);
+                mIconRequests.delete(seqNum);
+                for (IconCallback IconCallback : request.getCallbacks()) {
+                    IconCallback.onIconLoaded(request.mUri, bitmap);
                 }
-                mThumbnailCallbacks.remove(request);
             }
         });
     }
@@ -634,13 +636,13 @@
     }
 
     /**
-     * Callbacks for thumbnail loading.
+     * Callbacks for icon loading.
      */
-    public static abstract class ThumbnailCallback {
+    public static abstract class IconCallback {
         /**
-         * Called when the thumbnail is loaded.
+         * Called when the icon is loaded.
          */
-        public void onThumbnailLoaded(@NonNull Uri uri, @NonNull Bitmap bitmap) {
+        public void onIconLoaded(@NonNull Uri uri, @NonNull Bitmap bitmap) {
         }
 
         /**
@@ -650,48 +652,67 @@
         }
     }
 
-    private static class ThumbnailRequest {
-        Uri uri;
-        int width;
-        int height;
-        ThumbnailRequest(@NonNull Uri uri, int width, int height) {
+    private static class IconRequest {
+        final int mSeq;
+        final Uri mUri;
+        final int mWidth;
+        final int mHeight;
+        final List<IconCallback> mCallbacks;
+
+        /**
+         * Constructs an icon request.
+         * @param seq The unique sequence number assigned to the request by the media browser.
+         * @param uri The Uri for the icon.
+         * @param width The width for the icon.
+         * @param height The height for the icon.
+         */
+        IconRequest(int seq, @NonNull Uri uri, int width, int height) {
             if (uri == null) {
-                throw new IllegalArgumentException("thumbnail uri cannot be null");
+                throw new IllegalArgumentException("Icon uri cannot be null");
             }
-            this.uri = uri;
-            this.width = width;
-            this.height = height;
+            this.mSeq = seq;
+            this.mUri = uri;
+            this.mWidth = width;
+            this.mHeight = height;
+            mCallbacks = new ArrayList<IconCallback>();
         }
 
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (!(o instanceof ThumbnailRequest)) return false;
-
-            ThumbnailRequest that = (ThumbnailRequest) o;
-
-            if (height != that.height) return false;
-            if (width != that.width) return false;
-            if (!uri.equals(that.uri)) return false;
-
-            return true;
+        /**
+         * Adds a callback to the icon request.
+         * If the callback already exists, it will not be added again.
+         */
+        public void addCallback(@NonNull IconCallback callback) {
+            if (callback == null) {
+                throw new IllegalArgumentException("callback cannot be null in IconRequest");
+            }
+            if (!mCallbacks.contains(callback)) {
+                mCallbacks.add(callback);
+            }
         }
 
-        @Override
-        public int hashCode() {
-            int result = uri.hashCode();
-            result = 31 * result + width;
-            result = 31 * result + height;
-            return result;
+        /**
+         * Checks if the icon request has the same uri, width, and height as the given values.
+         */
+        public boolean isSameRequest(@Nullable Uri uri, int width, int height) {
+            return Objects.equals(mUri, uri) && mWidth == width && mHeight == height;
         }
 
         @Override
         public String toString() {
-            return "ThumbnailRequest{" +
-                    "uri=" + uri +
-                    ", width=" + width +
-                    ", height=" + height +
-                    '}';
+            final StringBuilder sb = new StringBuilder("IconRequest{");
+            sb.append("uri=").append(mUri);
+            sb.append(", width=").append(mWidth);
+            sb.append(", height=").append(mHeight);
+            sb.append(", seq=").append(mSeq);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        /**
+         * Gets an unmodifiable view of the list of callbacks associated with the request.
+         */
+        public List<IconCallback> getCallbacks() {
+            return Collections.unmodifiableList(mCallbacks);
         }
     }
 
@@ -822,11 +843,10 @@
         }
 
         @Override
-        public void onLoadThumbnail(final Uri uri, int width, int height, final Bitmap bitmap) {
+        public void onLoadIcon(final int seqNum, final Bitmap bitmap) {
             MediaBrowser mediaBrowser = mMediaBrowser.get();
             if (mediaBrowser != null) {
-                ThumbnailRequest request = new ThumbnailRequest(uri, width, height);
-                mediaBrowser.onLoadThumbnail(this, request, bitmap);
+                mediaBrowser.onLoadIcon(this, seqNum, bitmap);
             }
         }
     }
diff --git a/media/java/android/media/browse/MediaBrowserItem.java b/media/java/android/media/browse/MediaBrowserItem.java
index 38e765f..d0a0342 100644
--- a/media/java/android/media/browse/MediaBrowserItem.java
+++ b/media/java/android/media/browse/MediaBrowserItem.java
@@ -16,6 +16,7 @@
 
 package android.media.browse;
 
+import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -32,11 +33,11 @@
  */
 public final class MediaBrowserItem implements Parcelable {
     private final Uri mUri;
-    private final Uri mIconUri;
-    private final int mIconResId;
     private final int mFlags;
     private final CharSequence mTitle;
     private final CharSequence mSummary;
+    private final Uri mIconUri;
+    private final int mIconResourceId;
     private final Bundle mExtras;
 
     /** @hide */
@@ -61,8 +62,8 @@
     /**
      * Initialize a MediaBrowserItem object.
      */
-    private MediaBrowserItem(@NonNull Uri uri, @Nullable Uri iconUri, int iconResId, int flags,
-            @NonNull CharSequence title, CharSequence summary, Bundle extras) {
+    private MediaBrowserItem(@NonNull Uri uri, int flags, @NonNull CharSequence title,
+            CharSequence summary, @Nullable Uri iconUri, int iconResourceId, Bundle extras) {
         if (uri == null) {
             throw new IllegalArgumentException("uri can not be null");
         }
@@ -70,11 +71,11 @@
             throw new IllegalArgumentException("title can not be null");
         }
         mUri = uri;
-        mIconUri = iconUri;
-        mIconResId = iconResId;
         mFlags = flags;
         mTitle = title;
         mSummary = summary;
+        mIconUri = iconUri;
+        mIconResourceId = iconResourceId;
         mExtras = extras;
     }
 
@@ -83,8 +84,6 @@
      */
     private MediaBrowserItem(Parcel in) {
         mUri = Uri.CREATOR.createFromParcel(in);
-        mIconUri = Uri.CREATOR.createFromParcel(in);
-        mIconResId = in.readInt();
         mFlags = in.readInt();
         mTitle = in.readCharSequence();
         if (in.readInt() != 0) {
@@ -93,6 +92,12 @@
             mSummary = null;
         }
         if (in.readInt() != 0) {
+            mIconUri = Uri.CREATOR.createFromParcel(in);
+        } else {
+            mIconUri = null;
+        }
+        mIconResourceId = in.readInt();
+        if (in.readInt() != 0) {
             mExtras = Bundle.CREATOR.createFromParcel(in);
         } else {
             mExtras = null;
@@ -107,8 +112,6 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         mUri.writeToParcel(out, flags);
-        mIconUri.writeToParcel(out, flags);
-        out.writeInt(mIconResId);
         out.writeInt(mFlags);
         out.writeCharSequence(mTitle);
         if (mSummary != null) {
@@ -117,6 +120,13 @@
         } else {
             out.writeInt(0);
         }
+        if (mIconUri != null) {
+            out.writeInt(1);
+            mIconUri.writeToParcel(out, flags);
+        } else {
+            out.writeInt(0);
+        }
+        out.writeInt(mIconResourceId);
         if (mExtras != null) {
             out.writeInt(1);
             mExtras.writeToParcel(out, flags);
@@ -127,16 +137,16 @@
 
     public static final Parcelable.Creator<MediaBrowserItem> CREATOR =
             new Parcelable.Creator<MediaBrowserItem>() {
-        @Override
-        public MediaBrowserItem createFromParcel(Parcel in) {
-            return new MediaBrowserItem(in);
-        }
+                @Override
+                public MediaBrowserItem createFromParcel(Parcel in) {
+                    return new MediaBrowserItem(in);
+                }
 
-        @Override
-        public MediaBrowserItem[] newArray(int size) {
-            return new MediaBrowserItem[size];
-        }
-    };
+                @Override
+                public MediaBrowserItem[] newArray(int size) {
+                    return new MediaBrowserItem[size];
+                }
+            };
 
     /**
      * Gets the Uri of the item.
@@ -146,20 +156,6 @@
     }
 
     /**
-     * Gets the Uri of the icon.
-     */
-    public @Nullable Uri getIconUri() {
-        return mIconUri;
-    }
-
-    /**
-     * Gets the resource id of the icon.
-     */
-    public int getIconResId() {
-        return mIconResId;
-    }
-
-    /**
      * Gets the flags of the item.
      */
     public @Flags int getFlags() {
@@ -203,6 +199,20 @@
     }
 
     /**
+     * Gets the Uri of the icon.
+     */
+    public @Nullable Uri getIconUri() {
+        return mIconUri;
+    }
+
+    /**
+     * Gets the resource id of the icon.
+     */
+    public @DrawableRes int getIconResourceId() {
+        return mIconResourceId;
+    }
+
+    /**
      * Gets additional service-specified extras about the
      * item or its content, or null if none.
      */
@@ -217,9 +227,9 @@
         private final Uri mUri;
         private final int mFlags;
         private final CharSequence mTitle;
-        private Uri mIconUri;
-        private int mIconResId;
         private CharSequence mSummary;
+        private Uri mIconUri;
+        private int mIconResourceId;
         private Bundle mExtras;
 
         /**
@@ -238,10 +248,18 @@
         }
 
         /**
+         * Sets summary of the item, or null if none.
+         */
+        public @NonNull Builder setSummary(@Nullable CharSequence summary) {
+            mSummary = summary;
+            return this;
+        }
+
+        /**
          * Sets the uri of the icon.
          * <p>
-         * If both {@link #setIconUri(Uri)} and {@link #setIconResId(int)} are called,
-         * the resource id will be used to load the icon.
+         * Either {@link #setIconUri(Uri)} or {@link #setIconResourceId(int)} should be called.
+         * If both are specified, the resource id will be used to load the icon.
          * </p>
          */
         public @NonNull Builder setIconUri(@Nullable Uri iconUri) {
@@ -251,35 +269,31 @@
 
         /**
          * Sets the resource id of the icon.
+         * <p>
+         * Either {@link #setIconUri(Uri)} or {@link #setIconResourceId(int)} should be specified.
+         * If both are specified, the resource id will be used to load the icon.
+         * </p>
          */
-        public @NonNull Builder setIconResId(int resId) {
-            mIconResId = resId;
+        public @NonNull Builder setIconResourceId(@DrawableRes int ResourceId) {
+            mIconResourceId = ResourceId;
             return this;
         }
 
         /**
-         * Sets summary of the item, or null if none.
+         * Sets additional service-specified extras about the
+         * item or its content.
          */
-        public @NonNull Builder setSummary(@Nullable CharSequence summary) {
-            mSummary = summary;
-            return this;
-        }
-
-        /**
-        * Sets additional service-specified extras about the
-        * item or its content, or null if none.
-        */
         public @NonNull Builder setExtras(@Nullable Bundle extras) {
             mExtras = extras;
             return this;
         }
 
         /**
-        * Builds the item.
-        */
+         * Builds the item.
+         */
         public @NonNull MediaBrowserItem build() {
-            return new MediaBrowserItem(mUri, mIconUri, mIconResId,
-                    mFlags, mTitle, mSummary, mExtras);
+            return new MediaBrowserItem(mUri, mFlags, mTitle, mSummary, mIconUri,
+                    mIconResourceId, mExtras);
         }
     }
 }
diff --git a/media/java/android/media/browse/MediaBrowserService.java b/media/java/android/media/browse/MediaBrowserService.java
index 57befe7..99126c9 100644
--- a/media/java/android/media/browse/MediaBrowserService.java
+++ b/media/java/android/media/browse/MediaBrowserService.java
@@ -70,6 +70,13 @@
  */
 public abstract class MediaBrowserService extends Service {
     private static final String TAG = "MediaBrowserService";
+    private static final boolean DBG = false;
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_ACTION = "android.media.browse.MediaBrowserService";
 
     private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap();
     private final Handler mHandler = new Handler();
@@ -88,10 +95,65 @@
     }
 
     /**
-     * The {@link Intent} that must be declared as handled by the service.
+     * Completion handler for asynchronous callback methods in {@link MediaBrowserService}.
+     * <p>
+     * Each of the methods that takes one of these to send the result must call
+     * {@link #sendResult} to respond to the caller with the given results.  If those
+     * functions return without calling {@link #sendResult}, they must instead call
+     * {@link #detach} before returning, and then may call {@link #sendResult} when
+     * they are done.  If more than one of those methods is called, an exception will
+     * be thrown.
+     *
+     * @see MediaBrowserService#onLoadChildren
+     * @see MediaBrowserService#onLoadIcon
      */
-    @SdkConstant(SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_ACTION = "android.media.browse.MediaBrowserService";
+    public class Result<T> {
+        private Object mDebug;
+        private boolean mDetachCalled;
+        private boolean mSendResultCalled;
+
+        Result(Object debug) {
+            mDebug = debug;
+        }
+
+        /**
+         * Send the result back to the caller.
+         */
+        public void sendResult(T result) {
+            if (mSendResultCalled) {
+                throw new IllegalStateException("sendResult() called twice for: " + mDebug);
+            }
+            mSendResultCalled = true;
+            onResultSent(result);
+        }
+
+        /**
+         * Detach this message from the current thread and allow the {@link #sendResult}
+         * call to happen later.
+         */
+        public void detach() {
+            if (mDetachCalled) {
+                throw new IllegalStateException("detach() called when detach() had already"
+                        + " been called for: " + mDebug);
+            }
+            if (mSendResultCalled) {
+                throw new IllegalStateException("detach() called when sendResult() had already"
+                        + " been called for: " + mDebug);
+            }
+            mDetachCalled = true;
+        }
+
+        boolean isDone() {
+            return mDetachCalled || mSendResultCalled;
+        }
+
+        /**
+         * Called when the result is sent, after assertions about not being called twice
+         * have happened.
+         */
+        void onResultSent(T result) {
+        }
+    }
 
     private class ServiceBinder extends IMediaBrowserService.Stub {
         @Override
@@ -204,16 +266,53 @@
         }
 
         @Override
-        public void loadThumbnail(final Uri uri, final int width, final int height,
+        public void loadIcon(final int seq, final Uri uri, final int width, final int height,
                 final IMediaBrowserServiceCallbacks callbacks) {
+            if (uri == null) {
+                throw new IllegalStateException("loadIcon sent null list for uri " + uri);
+            }
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    Bitmap bitmap = onGetThumbnail(uri, width, height);
-                    try {
-                        callbacks.onLoadThumbnail(uri, width, height, bitmap);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "RemoteException in calling onLoadThumbnail", e);
+                    // In theory we could return a result to a new connection, but in practice
+                    // the other side in MediaBrowser uses a new IMediaBrowserServiceCallbacks
+                    // object every time it calls connect(), so as long as it does that we won't
+                    // see results sent for the wrong connection.
+                    final ConnectionRecord connection = mConnections.get(callbacks.asBinder());
+                    if (connection == null) {
+                        if (DBG) {
+                            Log.d(TAG, "Not loading bitmap for invalid connection. uri=" + uri);
+                        }
+                        return;
+                    }
+
+                    final Result<Bitmap> result = new Result<Bitmap>(uri) {
+                        @Override
+                        void onResultSent(Bitmap bitmap) {
+                            if (mConnections.get(connection.callbacks.asBinder()) != connection) {
+                                if (DBG) {
+                                    Log.d(TAG, "Not sending onLoadIcon result for connection"
+                                            + " that has been disconnected. pkg=" + connection.pkg
+                                            + " uri=" + uri);
+                                }
+                                return;
+                            }
+
+                            try {
+                                callbacks.onLoadIcon(seq, bitmap);
+                            } catch (RemoteException e) {
+                                // The other side is in the process of crashing.
+                                Log.w(TAG, "RemoteException in calling onLoadIcon", e);
+                            }
+                        }
+                    };
+
+                    onLoadIcon(uri, width, height, result);
+
+                    if (!result.isDone()) {
+                        throw new IllegalStateException("onLoadIcon must call detach() or"
+                                + " sendResult() before returning for package=" + connection.pkg
+                                + " uri=" + uri);
                     }
                 }
             });
@@ -256,29 +355,43 @@
      * for browsing, or null if none.  The contents of this bundle may affect
      * the information returned when browsing.
      */
-    protected abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
+    public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
             int clientUid, @Nullable Bundle rootHints);
 
     /**
      * Called to get information about the children of a media item.
+     * <p>
+     * Implementations must call result.{@link Result#sendResult result.sendResult} with the list
+     * of children. If loading the children will be an expensive operation that should be performed
+     * on another thread, result.{@link Result#detach result.detach} may be called before returning
+     * from this function, and then {@link Result#sendResult result.sendResult} called when
+     * the loading is complete.
      *
      * @param parentUri The uri of the parent media item whose
      * children are to be queried.
      * @return The list of children, or null if the uri is invalid.
      */
-    protected abstract @Nullable List<MediaBrowserItem> onLoadChildren(@NonNull Uri parentUri);
+    public abstract void onLoadChildren(@NonNull Uri parentUri,
+            @NonNull Result<List<MediaBrowserItem>> result);
 
     /**
-     * Called to get the thumbnail of a particular media item.
+     * Called to get the icon of a particular media item.
+     * <p>
+     * Implementations must call result.{@link Result#sendResult result.sendResult} with the bitmap.
+     * If loading the bitmap will be an expensive operation that should be performed
+     * on another thread, result.{@link Result#detach result.detach} may be called before returning
+     * from this function, and then {@link Result#sendResult result.sendResult} called when
+     * the loading is complete.
      *
      * @param uri The uri of the media item.
      * @param width The requested width of the icon in dp.
      * @param height The requested height of the icon in dp.
      *
-     * @return The file descriptor of the thumbnail, which may then be loaded
-     *          using a bitmap factory, or null if the item does not have a thumbnail.
+     * @return The file descriptor of the icon, which may then be loaded
+     *          using a bitmap factory, or null if the item does not have an icon.
      */
-    protected abstract @Nullable Bitmap onGetThumbnail(@NonNull Uri uri, int width, int height);
+    public abstract void onLoadIcon(@NonNull Uri uri, int width, int height,
+            @NonNull Result<Bitmap> result);
 
     /**
      * Call to set the media session.
@@ -311,20 +424,21 @@
      * @param parentUri The uri of the parent media item whose
      * children changed.
      */
-    public void notifyChildrenChanged(@NonNull Uri parentUri) {
+    public void notifyChildrenChanged(@NonNull final Uri parentUri) {
         if (parentUri == null) {
             throw new IllegalArgumentException("parentUri cannot be null in notifyChildrenChanged");
         }
-        for (IBinder binder : mConnections.keySet()) {
-            ConnectionRecord connection = mConnections.get(binder);
-            Set<Uri> uris = connection.subscriptions;
-            for (Uri uri : uris) {
-                if (uri.equals(parentUri)) {
-                    performLoadChildren(uri, connection);
-                    break;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                for (IBinder binder : mConnections.keySet()) {
+                    ConnectionRecord connection = mConnections.get(binder);
+                    if (connection.subscriptions.contains(parentUri)) {
+                        performLoadChildren(parentUri, connection);
+                    }
                 }
             }
-        }
+        });
     }
 
     /**
@@ -362,27 +476,54 @@
      * Call onLoadChildren and then send the results back to the connection.
      * <p>
      * Callers must make sure that this connection is still connected.
-     * <p>
-     * TODO: Think about caching and combining these calls.
      */
-    private void performLoadChildren(Uri uri, ConnectionRecord connection) {
-        final List<MediaBrowserItem> list = onLoadChildren(uri);
-        if (list == null) {
-            throw new IllegalStateException("onLoadChildren returned null for uri " + uri);
-        }
-        final ParceledListSlice<MediaBrowserItem> pls = new ParceledListSlice(list);
-        try {
-            connection.callbacks.onLoadChildren(uri, pls);
-        } catch (RemoteException ex) {
-            // The other side is in the process of crashing.
-            Log.w(TAG, "Calling onLoadChildren() failed for uri=" + uri
-                    + " package=" + connection.pkg);
+    private void performLoadChildren(final Uri uri, final ConnectionRecord connection) {
+        final Result<List<MediaBrowserItem>> result = new Result<List<MediaBrowserItem>>(uri) {
+            @Override
+            void onResultSent(List<MediaBrowserItem> list) {
+                if (list == null) {
+                    throw new IllegalStateException("onLoadChildren sent null list for uri " + uri);
+                }
+                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
+                    if (DBG) {
+                        Log.d(TAG, "Not sending onLoadChildren result for connection that has"
+                                + " been disconnected. pkg=" + connection.pkg + " uri=" + uri);
+                    }
+                    return;
+                }
+
+                final ParceledListSlice<MediaBrowserItem> pls = new ParceledListSlice(list);
+                try {
+                    connection.callbacks.onLoadChildren(uri, pls);
+                } catch (RemoteException ex) {
+                    // The other side is in the process of crashing.
+                    Log.w(TAG, "Calling onLoadChildren() failed for uri=" + uri
+                            + " package=" + connection.pkg);
+                }
+            }
+        };
+
+        onLoadChildren(uri, result);
+
+        if (!result.isDone()) {
+            throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
+                    + " before returning for package=" + connection.pkg + " uri=" + uri);
         }
     }
 
-    public static class BrowserRoot {
+    /**
+     * Contains information that the browser service needs to send to the client
+     * when first connected.
+     */
+    public static final class BrowserRoot {
         final private Uri mUri;
         final private Bundle mExtras;
+
+        /**
+         * Constructs a browser root.
+         * @param uri The root Uri for browsing.
+         * @param extras Any extras about the browser service.
+         */
         public BrowserRoot(@NonNull Uri uri, @Nullable Bundle extras) {
             if (uri == null) {
                 throw new IllegalArgumentException("The root uri in BrowserRoot cannot be null. " +
@@ -392,11 +533,17 @@
             mExtras = extras;
         }
 
-        Uri getRootUri() {
+        /**
+         * Gets the root uri for browsing.
+         */
+        public Uri getRootUri() {
             return mUri;
         }
 
-        Bundle getExtras() {
+        /**
+         * Gets any extras about the brwoser service.
+         */
+        public Bundle getExtras() {
             return mExtras;
         }
     }
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index d87a69e..af3b72e 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -15,12 +15,14 @@
 
 package android.media.session;
 
-import android.content.ComponentName;
+import android.app.PendingIntent;
+import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
 import android.media.routing.IMediaRouter;
 import android.media.session.ISessionController;
 import android.media.session.PlaybackState;
+import android.media.session.MediaSession;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 
@@ -34,12 +36,16 @@
     void setFlags(int flags);
     void setActive(boolean active);
     void setMediaRouter(in IMediaRouter router);
-    void setMediaButtonReceiver(in ComponentName mbr);
+    void setMediaButtonReceiver(in PendingIntent mbr);
+    void setLaunchPendingIntent(in PendingIntent pi);
     void destroy();
 
     // These commands are for the TransportPerformer
     void setMetadata(in MediaMetadata metadata);
     void setPlaybackState(in PlaybackState state);
+    void setQueue(in ParceledListSlice queue);
+    void setQueueTitle(CharSequence title);
+    void setExtras(in Bundle extras);
     void setRatingType(int type);
 
     // These commands relate to volume handling
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 39391b6..9911129 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -17,6 +17,7 @@
 
 import android.media.Rating;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 
@@ -24,11 +25,14 @@
  * @hide
  */
 oneway interface ISessionCallback {
-    void onCommand(String command, in Bundle extras, in ResultReceiver cb);
+    void onCommand(String command, in Bundle args, in ResultReceiver cb);
     void onMediaButton(in Intent mediaButtonIntent, int sequenceNumber, in ResultReceiver cb);
 
     // These callbacks are for the TransportPerformer
     void onPlay();
+    void onPlayUri(in Uri uri, in Bundle extras);
+    void onPlayFromSearch(String query, in Bundle extras);
+    void onSkipToTrack(long id);
     void onPause();
     void onStop();
     void onNext();
@@ -37,6 +41,7 @@
     void onRewind();
     void onSeekTo(long pos);
     void onRate(in Rating rating);
+    void onCustomAction(String action, in Bundle args);
 
     // These callbacks are for volume handling
     void onAdjustVolume(int direction);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index b555220..3518458 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -15,30 +15,37 @@
 
 package android.media.session;
 
+import android.app.PendingIntent;
 import android.content.Intent;
+import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.routing.IMediaRouterDelegate;
 import android.media.routing.IMediaRouterStateCallback;
 import android.media.session.ISessionControllerCallback;
-import android.media.session.MediaSessionInfo;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
+import android.media.session.MediaSession;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.view.KeyEvent;
 
+import java.util.List;
+
 /**
  * Interface to a MediaSession in the system.
  * @hide
  */
 interface ISessionController {
-    void sendCommand(String command, in Bundle extras, in ResultReceiver cb);
+    void sendCommand(String command, in Bundle args, in ResultReceiver cb);
     boolean sendMediaButton(in KeyEvent mediaButton);
     void registerCallbackListener(in ISessionControllerCallback cb);
     void unregisterCallbackListener(in ISessionControllerCallback cb);
     boolean isTransportControlEnabled();
-    MediaSessionInfo getSessionInfo();
+    String getPackageName();
+    String getTag();
+    PendingIntent getLaunchPendingIntent();
     long getFlags();
     ParcelableVolumeInfo getVolumeAttributes();
     void adjustVolume(int direction, int flags);
@@ -48,6 +55,9 @@
 
     // These commands are for the TransportControls
     void play();
+    void playUri(in Uri uri, in Bundle extras);
+    void playFromSearch(String string, in Bundle extras);
+    void skipToTrack(long id);
     void pause();
     void stop();
     void next();
@@ -56,7 +66,11 @@
     void rewind();
     void seekTo(long pos);
     void rate(in Rating rating);
+    void sendCustomAction(String action, in Bundle args);
     MediaMetadata getMetadata();
     PlaybackState getPlaybackState();
+    ParceledListSlice getQueue();
+    CharSequence getQueueTitle();
+    Bundle getExtras();
     int getRatingType();
 }
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index 64d2bc7..78cd699 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -15,9 +15,11 @@
 
 package android.media.session;
 
+import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
+import android.media.session.MediaSession;
 import android.os.Bundle;
 
 /**
@@ -29,5 +31,8 @@
     // These callbacks are for the TransportController
     void onPlaybackStateChanged(in PlaybackState state);
     void onMetadataChanged(in MediaMetadata metadata);
+    void onQueueChanged(in ParceledListSlice queue);
+    void onQueueTitleChanged(CharSequence title);
+    void onExtrasChanged(in Bundle extras);
     void onVolumeInfoChanged(in ParcelableVolumeInfo info);
 }
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 171f4c9..382579c 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -18,12 +18,16 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.routing.MediaRouter;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -36,6 +40,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Allows an app to interact with an ongoing media session. Media buttons and
@@ -55,15 +60,21 @@
     private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
     private static final int MSG_UPDATE_METADATA = 3;
     private static final int MSG_UPDATE_VOLUME = 4;
+    private static final int MSG_UPDATE_QUEUE = 5;
+    private static final int MSG_UPDATE_QUEUE_TITLE = 6;
+    private static final int MSG_UPDATE_EXTRAS = 7;
 
     private final ISessionController mSessionBinder;
 
+    private final MediaSession.Token mToken;
+    private final Context mContext;
     private final CallbackStub mCbStub = new CallbackStub(this);
     private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
     private final Object mLock = new Object();
 
     private boolean mCbRegistered = false;
-    private MediaSessionInfo mInfo;
+    private String mPackageName;
+    private String mTag;
 
     private final TransportControls mTransportControls;
 
@@ -73,21 +84,27 @@
      *
      * @hide
      */
-    public MediaController(ISessionController sessionBinder) {
+    public MediaController(Context context, ISessionController sessionBinder) {
         if (sessionBinder == null) {
             throw new IllegalArgumentException("Session token cannot be null");
         }
+        if (context == null) {
+            throw new IllegalArgumentException("Context cannot be null");
+        }
         mSessionBinder = sessionBinder;
         mTransportControls = new TransportControls();
+        mToken = new MediaSession.Token(sessionBinder);
+        mContext = context;
     }
 
     /**
      * Create a new MediaController from a session's token.
      *
+     * @param context The caller's context.
      * @param token The token for the session.
      */
-    public MediaController(@NonNull MediaSession.Token token) {
-        this(token.getBinder());
+    public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
+        this(context, token.getBinder());
     }
 
     /**
@@ -162,6 +179,23 @@
     }
 
     /**
+     * Get the current play queue for this session.
+     *
+     * @return The current play queue or null.
+     */
+    public @Nullable List<MediaSession.Track> getQueue() {
+        try {
+            ParceledListSlice queue = mSessionBinder.getQueue();
+            if (queue != null) {
+                return queue.getList();
+            }
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getQueue.", e);
+        }
+        return null;
+    }
+
+    /**
      * Get the rating type supported by the session. One of:
      * <ul>
      * <li>{@link Rating#RATING_NONE}</li>
@@ -185,12 +219,11 @@
     }
 
     /**
-     * Get the flags for this session.
+     * Get the flags for this session. Flags are defined in {@link MediaSession}.
      *
      * @return The current set of flags for the session.
-     * @hide
      */
-    public long getFlags() {
+    public @MediaSession.SessionFlags long getFlags() {
         try {
             return mSessionBinder.getFlags();
         } catch (RemoteException e) {
@@ -217,6 +250,30 @@
     }
 
     /**
+     * Get an intent for launching UI associated with this session if one
+     * exists.
+     *
+     * @return A {@link PendingIntent} to launch UI or null.
+     */
+    public @Nullable PendingIntent getLaunchActivity() {
+        try {
+            return mSessionBinder.getLaunchPendingIntent();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getPendingIntent.", e);
+        }
+        return null;
+    }
+
+    /**
+     * Get the token for the session this is connected to.
+     *
+     * @return The token for the connected session.
+     */
+    public @NonNull MediaSession.Token getSessionToken() {
+        return mToken;
+    }
+
+    /**
      * Set the volume of the output this session is playing on. The command will
      * be ignored if it does not support
      * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
@@ -306,36 +363,52 @@
      * commands should only be sent to sessions that the controller owns.
      *
      * @param command The command to send
-     * @param params Any parameters to include with the command
+     * @param args Any parameters to include with the command
      * @param cb The callback to receive the result on
      */
-    public void sendControlCommand(@NonNull String command, @Nullable Bundle params,
+    public void sendCommand(@NonNull String command, @Nullable Bundle args,
             @Nullable ResultReceiver cb) {
         if (TextUtils.isEmpty(command)) {
             throw new IllegalArgumentException("command cannot be null or empty");
         }
         try {
-            mSessionBinder.sendCommand(command, params, cb);
+            mSessionBinder.sendCommand(command, args, cb);
         } catch (RemoteException e) {
             Log.d(TAG, "Dead object in sendCommand.", e);
         }
     }
 
     /**
-     * Get the info for the session this controller is connected to.
+     * Get the session owner's package name.
      *
-     * @return The session info for the connected session.
-     * @hide
+     * @return The package name of of the session owner.
      */
-    public MediaSessionInfo getSessionInfo() {
-        if (mInfo == null) {
+    public String getPackageName() {
+        if (mPackageName == null) {
             try {
-                mInfo = mSessionBinder.getSessionInfo();
+                mPackageName = mSessionBinder.getPackageName();
             } catch (RemoteException e) {
-                Log.e(TAG, "Error in getSessionInfo.", e);
+                Log.d(TAG, "Dead object in getPackageName.", e);
             }
         }
-        return mInfo;
+        return mPackageName;
+    }
+
+    /**
+     * Get the session's tag for debugging purposes.
+     *
+     * @return The session's tag.
+     * @hide
+     */
+    public String getTag() {
+        if (mTag == null) {
+            try {
+                mTag = mSessionBinder.getTag();
+            } catch (RemoteException e) {
+                Log.d(TAG, "Dead object in getTag.", e);
+            }
+        }
+        return mTag;
     }
 
     /*
@@ -438,6 +511,34 @@
         }
 
         /**
+         * Override to handle changes to tracks in the queue.
+         *
+         * @param queue A list of tracks in the current play queue. It should include the currently
+         *              playing track as well as previous and upcoming tracks if applicable.
+         * @see MediaSession.Track
+         */
+        public void onQueueChanged(@Nullable List<MediaSession.Track> queue) {
+        }
+
+        /**
+         * Override to handle changes to the queue title.
+         *
+         * @param title The title that should be displayed along with the play queue such as
+         *              "Now Playing". May be null if there is no such title.
+         */
+        public void onQueueTitleChanged(@Nullable CharSequence title) {
+        }
+
+        /**
+         * Override to handle changes to the {@link MediaSession} extras.
+         *
+         * @param extras The extras that can include other information associated with the
+         *               {@link MediaSession}.
+         */
+        public void onExtrasChanged(@Nullable Bundle extras) {
+        }
+
+        /**
          * Override to handle changes to the volume info.
          *
          * @param info The current volume info for this session.
@@ -468,6 +569,54 @@
         }
 
         /**
+         * Request that the player start playback for a specific {@link Uri}.
+         *
+         * @param uri The uri of the requested media.
+         * @param extras Optional extras that can include extra information about the media item
+         *               to be played.
+         */
+        public void playUri(Uri uri, Bundle extras) {
+            if (uri == null) {
+                throw new IllegalArgumentException("You must specify a non-null Uri for playUri.");
+            }
+            try {
+                mSessionBinder.playUri(uri, extras);
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling play(" + uri + ").", e);
+            }
+        }
+
+        /**
+         * Request that the player start playback for a specific search query.
+         *
+         * @param query The search query.
+         * @param extras Optional extras that can include extra information about the query.
+         */
+        public void playFromSearch(String query, Bundle extras) {
+            if (TextUtils.isEmpty(query)) {
+                throw new IllegalArgumentException(
+                        "You must specify a non-empty search query for playFromSearch.");
+            }
+            try {
+                mSessionBinder.playFromSearch(query, extras);
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling play(" + query + ").", e);
+            }
+        }
+
+        /**
+         * Play a track with a specific id in the play queue.
+         * If you specify an id that is not in the play queue, the behavior is undefined.
+         */
+        public void skipToTrack(long id) {
+            try {
+                mSessionBinder.skipToTrack(id);
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling skipToTrack(" + id + ").", e);
+            }
+        }
+
+        /**
          * Request that the player pause its playback and stay at its current
          * position.
          */
@@ -564,6 +713,41 @@
                 Log.wtf(TAG, "Error calling rate.", e);
             }
         }
+
+        /**
+         * Send a custom action back for the {@link MediaSession} to perform.
+         *
+         * @param customAction The action to perform.
+         * @param args Optional arguments to supply to the {@link MediaSession} for this
+         *             custom action.
+         */
+        public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
+                    @Nullable Bundle args) {
+            if (customAction == null) {
+                throw new IllegalArgumentException("CustomAction cannot be null.");
+            }
+            sendCustomAction(customAction.getAction(), args);
+        }
+
+        /**
+         * Send the id and args from a custom action back for the {@link MediaSession} to perform.
+         *
+         * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args)
+         * @param action The action identifier of the {@link PlaybackState.CustomAction} as
+         *               specified by the {@link MediaSession}.
+         * @param args Optional arguments to supply to the {@link MediaSession} for this
+         *             custom action.
+         */
+        public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
+            if (TextUtils.isEmpty(action)) {
+                throw new IllegalArgumentException("CustomAction cannot be null.");
+            }
+            try {
+                mSessionBinder.sendCustomAction(action, args);
+            } catch (RemoteException e) {
+                Log.d(TAG, "Dead object in sendCustomAction.", e);
+            }
+        }
     }
 
     /**
@@ -678,6 +862,31 @@
         }
 
         @Override
+        public void onQueueChanged(ParceledListSlice parceledQueue) {
+            List<MediaSession.Track> queue = parceledQueue.getList();
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
+            }
+        }
+
+        @Override
+        public void onQueueTitleChanged(CharSequence title) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null);
+            }
+        }
+
+        @Override
+        public void onExtrasChanged(Bundle extras) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_EXTRAS, extras, null);
+            }
+        }
+
+        @Override
         public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
             MediaController controller = mController.get();
             if (controller != null) {
@@ -709,6 +918,15 @@
                 case MSG_UPDATE_METADATA:
                     mCallback.onMetadataChanged((MediaMetadata) msg.obj);
                     break;
+                case MSG_UPDATE_QUEUE:
+                    mCallback.onQueueChanged((List<MediaSession.Track>) msg.obj);
+                    break;
+                case MSG_UPDATE_QUEUE_TITLE:
+                    mCallback.onQueueTitleChanged((CharSequence) msg.obj);
+                    break;
+                case MSG_UPDATE_EXTRAS:
+                    mCallback.onExtrasChanged((Bundle) msg.obj);
+                    break;
                 case MSG_UPDATE_VOLUME:
                     mCallback.onVolumeInfoChanged((VolumeInfo) msg.obj);
                     break;
diff --git a/media/java/android/media/session/MediaSession.aidl b/media/java/android/media/session/MediaSession.aidl
index 4a7efc2..0ad58c4 100644
--- a/media/java/android/media/session/MediaSession.aidl
+++ b/media/java/android/media/session/MediaSession.aidl
@@ -16,3 +16,4 @@
 package android.media.session;
 
 parcelable MediaSession.Token;
+parcelable MediaSession.Track;
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 6662303..cf8e3dd 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -16,21 +16,22 @@
 
 package android.media.session;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.routing.MediaRouter;
-import android.media.session.ISessionController;
-import android.media.session.ISession;
-import android.media.session.ISessionCallback;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -41,11 +42,10 @@
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.Log;
 
-import com.android.internal.telephony.DctConstants.Activity;
-
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -99,6 +99,14 @@
      */
     public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
+            FLAG_HANDLES_MEDIA_BUTTONS,
+            FLAG_HANDLES_TRANSPORT_CONTROLS,
+            FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
+    public @interface SessionFlags { }
+
     /**
      * The session uses local playback.
      */
@@ -112,6 +120,7 @@
     private final Object mLock = new Object();
 
     private final MediaSession.Token mSessionToken;
+    private final MediaController mController;
     private final ISession mBinder;
     private final CallbackStub mCbStub;
 
@@ -161,6 +170,7 @@
         try {
             mBinder = manager.createSession(mCbStub, tag, userId);
             mSessionToken = new Token(mBinder.getController());
+            mController = new MediaController(context, mSessionToken);
         } catch (RemoteException e) {
             throw new RuntimeException("Remote error creating session.", e);
         }
@@ -215,12 +225,17 @@
 
     /**
      * Set an intent for launching UI for this Session. This can be used as a
-     * quick link to an ongoing media screen.
+     * quick link to an ongoing media screen. The intent should be for an
+     * activity that may be started using {@link Activity#startActivity(Intent)}.
      *
      * @param pi The intent to launch to show UI for this Session.
      */
-    public void setLaunchPendingIntent(@Nullable PendingIntent pi) {
-        // TODO
+    public void setLaunchActivity(@Nullable PendingIntent pi) {
+        try {
+            mBinder.setLaunchPendingIntent(pi);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
+        }
     }
 
     /**
@@ -241,13 +256,14 @@
     }
 
     /**
-     * Set a media button event receiver component to use to restart playback
-     * after an app has been stopped.
+     * Set a pending intent for your media button receiver to allow restarting
+     * playback after the session has been stopped. If your app is started in
+     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
+     * the pending intent.
      *
-     * @param mbr The receiver component to send the media button event to.
-     * @hide
+     * @param mbr The {@link PendingIntent} to send the media button event to.
      */
-    public void setMediaButtonReceiver(@Nullable ComponentName mbr) {
+    public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
         try {
             mBinder.setMediaButtonReceiver(mbr);
         } catch (RemoteException e) {
@@ -260,7 +276,7 @@
      *
      * @param flags The flags to set for this session.
      */
-    public void setFlags(int flags) {
+    public void setFlags(@SessionFlags int flags) {
         try {
             mBinder.setFlags(flags);
         } catch (RemoteException e) {
@@ -395,6 +411,16 @@
     }
 
     /**
+     * Get a controller for this session. This is a convenience method to avoid
+     * having to cache your own controller in process.
+     *
+     * @return A controller for this session.
+     */
+    public @NonNull MediaController getController() {
+        return mController;
+    }
+
+    /**
      * Add a callback to receive transport controls on, such as play, rewind, or
      * fast forward.
      *
@@ -474,6 +500,54 @@
     }
 
     /**
+     * Update the list of tracks in the play queue. It is an ordered list and should contain the
+     * current track, and previous or upcoming tracks if they exist.
+     * Specify null if there is no current play queue.
+     * <p>
+     * The queue should be of reasonable size. If the play queue is unbounded within your
+     * app, it is better to send a reasonable amount in a sliding window instead.
+     *
+     * @param queue A list of tracks in the play queue.
+     */
+    public void setQueue(@Nullable List<Track> queue) {
+        try {
+            mBinder.setQueue(new ParceledListSlice<Track>(queue));
+        } catch (RemoteException e) {
+            Log.wtf("Dead object in setQueue.", e);
+        }
+    }
+
+    /**
+     * Set the title of the play queue. The UI should display this title along
+     * with the play queue itself.
+     * e.g. "Play Queue", "Now Playing", or an album name.
+     *
+     * @param title The title of the play queue.
+     */
+    public void setQueueTitle(@Nullable CharSequence title) {
+        try {
+            mBinder.setQueueTitle(title);
+        } catch (RemoteException e) {
+            Log.wtf("Dead object in setQueueTitle.", e);
+        }
+    }
+
+    /**
+     * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
+     * be made as to how a {@link MediaController} will handle these extras.
+     * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
+     *
+     * @param extras The extras associated with the {@link MediaSession}.
+     */
+    public void setExtras(@Nullable Bundle extras) {
+        try {
+            mBinder.setExtras(extras);
+        } catch (RemoteException e) {
+            Log.wtf("Dead object in setExtras.", e);
+        }
+    }
+
+    /**
      * Notify the system that the remote volume changed.
      *
      * @param provider The provider that is handling volume changes.
@@ -495,6 +569,18 @@
         postToTransportCallbacks(TransportMessageHandler.MSG_PLAY);
     }
 
+    private void dispatchPlayUri(Uri uri, Bundle extras) {
+        postToTransportCallbacks(TransportMessageHandler.MSG_PLAY_URI, uri, extras);
+    }
+
+    private void dispatchPlayFromSearch(String query, Bundle extras) {
+        postToTransportCallbacks(TransportMessageHandler.MSG_PLAY_SEARCH, query, extras);
+    }
+
+    private void dispatchSkipToTrack(long id) {
+        postToTransportCallbacks(TransportMessageHandler.MSG_SKIP_TO_TRACK, id);
+    }
+
     private void dispatchPause() {
         postToTransportCallbacks(TransportMessageHandler.MSG_PAUSE);
     }
@@ -527,6 +613,10 @@
         postToTransportCallbacks(TransportMessageHandler.MSG_RATE, rating);
     }
 
+    private void dispatchCustomAction(String action, Bundle args) {
+        postToTransportCallbacks(TransportMessageHandler.MSG_CUSTOM_ACTION, action, args);
+    }
+
     private TransportMessageHandler getTransportControlsHandlerForCallbackLocked(
             TransportControlsCallback callback) {
         for (int i = mTransportCallbacks.size() - 1; i >= 0; i--) {
@@ -556,6 +646,14 @@
         }
     }
 
+    private void postToTransportCallbacks(int what, Object obj, Bundle args) {
+        synchronized (mLock) {
+            for (int i = mTransportCallbacks.size() - 1; i >= 0; i--) {
+                mTransportCallbacks.get(i).post(what, obj, args);
+            }
+        }
+    }
+
     private void postToTransportCallbacks(int what) {
         postToTransportCallbacks(what, null);
     }
@@ -587,8 +685,8 @@
         return false;
     }
 
-    private void postCommand(String command, Bundle extras, ResultReceiver resultCb) {
-        Command cmd = new Command(command, extras, resultCb);
+    private void postCommand(String command, Bundle args, ResultReceiver resultCb) {
+        Command cmd = new Command(command, args, resultCb);
         synchronized (mLock) {
             for (int i = mCallbacks.size() - 1; i >= 0; i--) {
                 mCallbacks.get(i).post(CallbackMessageHandler.MSG_COMMAND, cmd);
@@ -629,6 +727,7 @@
      * the session.
      */
     public static final class Token implements Parcelable {
+
         private ISessionController mBinder;
 
         /**
@@ -648,6 +747,31 @@
             dest.writeStrongBinder(mBinder.asBinder());
         }
 
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            Token other = (Token) obj;
+            if (mBinder == null) {
+                if (other.mBinder != null)
+                    return false;
+            } else if (!mBinder.asBinder().equals(other.mBinder.asBinder()))
+                return false;
+            return true;
+        }
+
         ISessionController getBinder() {
             return mBinder;
         }
@@ -691,15 +815,15 @@
         }
 
         /**
-         * Called when a controller has sent a custom command to this session.
+         * Called when a controller has sent a command to this session.
          * The owner of the session may handle custom commands but is not
          * required to.
          *
          * @param command The command name.
-         * @param extras Optional parameters for the command, may be null.
+         * @param args Optional parameters for the command, may be null.
          * @param cb A result receiver to which a result may be sent by the command, may be null.
          */
-        public void onControlCommand(@NonNull String command, @Nullable Bundle extras,
+        public void onCommand(@NonNull String command, @Nullable Bundle args,
                 @Nullable ResultReceiver cb) {
         }
     }
@@ -717,6 +841,24 @@
         }
 
         /**
+         * Override to handle requests to play a specific {@link Uri}.
+         */
+        public void onPlayUri(Uri uri, Bundle extras) {
+        }
+
+        /**
+         * Override to handle requests to begin playback from a search query.
+         */
+        public void onPlayFromSearch(String query, Bundle extras) {
+        }
+
+        /**
+         * Override to handle requests to play a track with a given id from the play queue.
+         */
+        public void onSkipToTrack(long id) {
+        }
+
+        /**
          * Override to handle requests to pause playback.
          */
         public void onPause() {
@@ -767,6 +909,17 @@
          */
         public void onSetRating(@NonNull Rating rating) {
         }
+
+        /**
+         * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
+         * performed.
+         *
+         * @param action The action that was originally sent in the
+         *               {@link PlaybackState.CustomAction}.
+         * @param extras Optional extras specified by the {@link MediaController}.
+         */
+        public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
+        }
     }
 
     /**
@@ -780,10 +933,10 @@
         }
 
         @Override
-        public void onCommand(String command, Bundle extras, ResultReceiver cb) {
+        public void onCommand(String command, Bundle args, ResultReceiver cb) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.postCommand(command, extras, cb);
+                session.postCommand(command, args, cb);
             }
         }
 
@@ -811,6 +964,30 @@
         }
 
         @Override
+        public void onPlayUri(Uri uri, Bundle extras) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchPlayUri(uri, extras);
+            }
+        }
+
+        @Override
+        public void onPlayFromSearch(String query, Bundle extras) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchPlayFromSearch(query, extras);
+            }
+        }
+
+        @Override
+        public void onSkipToTrack(long id) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchSkipToTrack(id);
+            }
+        }
+
+        @Override
         public void onPause() {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -875,6 +1052,14 @@
         }
 
         @Override
+        public void onCustomAction(String action, Bundle args) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchCustomAction(action, args);
+            }
+        }
+
+        @Override
         public void onAdjustVolume(int direction) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -896,6 +1081,157 @@
 
     }
 
+    /**
+     * A single track that is part of the play queue. It contains information necessary to display
+     * a single track in the queue.
+     */
+    public static final class Track implements Parcelable {
+        /**
+         * This id is reserved. No tracks can be explicitly asigned this id.
+         */
+        public static final int UNKNOWN_ID = -1;
+
+        private final MediaMetadata mMetadata;
+        private final long mId;
+        private final Uri mUri;
+        private final Bundle mExtras;
+
+        /**
+         * Create a new {@link MediaSession.Track}.
+         *
+         * @param metadata The metadata for this track.
+         * @param id An identifier for this track. It must be unique within the play queue.
+         * @param uri The uri for this track.
+         * @param extras A bundle of extras that can be used to add extra information about the
+         *               track.
+         */
+        private Track(MediaMetadata metadata, long id, Uri uri, Bundle extras) {
+            mMetadata = metadata;
+            mId = id;
+            mUri = uri;
+            mExtras = extras;
+        }
+
+        private Track(Parcel in) {
+            mMetadata = MediaMetadata.CREATOR.createFromParcel(in);
+            mId = in.readLong();
+            mUri = Uri.CREATOR.createFromParcel(in);
+            mExtras = in.readBundle();
+        }
+
+        /**
+         * Get the metadata for this track.
+         */
+        public MediaMetadata getMetadata() {
+            return mMetadata;
+        }
+
+        /**
+         * Get the id for this track.
+         */
+        public long getId() {
+            return mId;
+        }
+
+        /**
+         * Get the Uri for this track.
+         */
+        public Uri getUri() {
+            return mUri;
+        }
+
+        /**
+         * Get the extras for this track.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+
+        /**
+         * Builder for {@link MediaSession.Track} objects.
+         */
+        public static final class Builder {
+            private final MediaMetadata mMetadata;
+            private final long mId;
+            private final Uri mUri;
+
+            private Bundle mExtras;
+
+            /**
+             * Create a builder with the metadata, id, and uri already set.
+             */
+            public Builder(MediaMetadata metadata, long id, Uri uri) {
+                if (metadata == null) {
+                    throw new IllegalArgumentException(
+                            "You must specify a non-null MediaMetadata to build a Track.");
+                }
+                if (uri == null) {
+                    throw new IllegalArgumentException(
+                            "You must specify a non-null Uri to build a Track.");
+                }
+                if (id == UNKNOWN_ID) {
+                    throw new IllegalArgumentException(
+                            "You must specify an id other than UNKNOWN_ID to build a Track.");
+                }
+                mMetadata = metadata;
+                mId = id;
+                mUri = uri;
+            }
+
+            /**
+             * Set optional extras for the track.
+             */
+            public MediaSession.Track.Builder setExtras(Bundle extras) {
+                mExtras = extras;
+                return this;
+            }
+
+            /**
+             * Create the {@link Track}.
+             */
+            public MediaSession.Track build() {
+                return new MediaSession.Track(mMetadata, mId, mUri, mExtras);
+            }
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mMetadata.writeToParcel(dest, flags);
+            dest.writeLong(mId);
+            mUri.writeToParcel(dest, flags);
+            dest.writeBundle(mExtras);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<MediaSession.Track> CREATOR
+                = new Creator<MediaSession.Track>() {
+
+            @Override
+            public MediaSession.Track createFromParcel(Parcel p) {
+                return new MediaSession.Track(p);
+            }
+
+            @Override
+            public MediaSession.Track[] newArray(int size) {
+                return new MediaSession.Track[size];
+            }
+        };
+
+        @Override
+        public String toString() {
+            return "MediaSession.Track {" +
+                    "Metadata=" + mMetadata +
+                    ", Id=" + mId +
+                    ", Uri=" + mUri +
+                    ", Extras=" + mExtras +
+                    " }";
+        }
+    }
+
     private class CallbackMessageHandler extends Handler {
         private static final int MSG_MEDIA_BUTTON = 1;
         private static final int MSG_COMMAND = 2;
@@ -919,7 +1255,7 @@
                         break;
                     case MSG_COMMAND:
                         Command cmd = (Command) msg.obj;
-                        mCallback.onControlCommand(cmd.command, cmd.extras, cmd.stub);
+                        mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
                         break;
                 }
             }
@@ -948,14 +1284,18 @@
 
     private class TransportMessageHandler extends Handler {
         private static final int MSG_PLAY = 1;
-        private static final int MSG_PAUSE = 2;
-        private static final int MSG_STOP = 3;
-        private static final int MSG_NEXT = 4;
-        private static final int MSG_PREVIOUS = 5;
-        private static final int MSG_FAST_FORWARD = 6;
-        private static final int MSG_REWIND = 7;
-        private static final int MSG_SEEK_TO = 8;
-        private static final int MSG_RATE = 9;
+        private static final int MSG_PLAY_URI = 2;
+        private static final int MSG_PLAY_SEARCH = 3;
+        private static final int MSG_SKIP_TO_TRACK = 4;
+        private static final int MSG_PAUSE = 5;
+        private static final int MSG_STOP = 6;
+        private static final int MSG_NEXT = 7;
+        private static final int MSG_PREVIOUS = 8;
+        private static final int MSG_FAST_FORWARD = 9;
+        private static final int MSG_REWIND = 10;
+        private static final int MSG_SEEK_TO = 11;
+        private static final int MSG_RATE = 12;
+        private static final int MSG_CUSTOM_ACTION = 13;
 
         private TransportControlsCallback mCallback;
 
@@ -964,6 +1304,12 @@
             mCallback = cb;
         }
 
+        public void post(int what, Object obj, Bundle bundle) {
+            Message msg = obtainMessage(what, obj);
+            msg.setData(bundle);
+            msg.sendToTarget();
+        }
+
         public void post(int what, Object obj) {
             obtainMessage(what, obj).sendToTarget();
         }
@@ -978,6 +1324,14 @@
                 case MSG_PLAY:
                     mCallback.onPlay();
                     break;
+                case MSG_PLAY_URI:
+                    mCallback.onPlayUri((Uri) msg.obj, msg.getData());
+                    break;
+                case MSG_PLAY_SEARCH:
+                    mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
+                    break;
+                case MSG_SKIP_TO_TRACK:
+                    mCallback.onSkipToTrack((Long) msg.obj);
                 case MSG_PAUSE:
                     mCallback.onPause();
                     break;
@@ -1002,6 +1356,9 @@
                 case MSG_RATE:
                     mCallback.onSetRating((Rating) msg.obj);
                     break;
+                case MSG_CUSTOM_ACTION:
+                    mCallback.onCustomAction((String) msg.obj, msg.getData());
+                    break;
             }
         }
     }
diff --git a/media/java/android/media/session/MediaSessionInfo.aidl b/media/java/android/media/session/MediaSessionInfo.aidl
deleted file mode 100644
index 63dca9a..0000000
--- a/media/java/android/media/session/MediaSessionInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media.session;
-
-parcelable MediaSessionInfo;
diff --git a/media/java/android/media/session/MediaSessionInfo.java b/media/java/android/media/session/MediaSessionInfo.java
deleted file mode 100644
index 4dc1c09..0000000
--- a/media/java/android/media/session/MediaSessionInfo.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.session;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Information about a media session, including the owner's package name.
- *
- * @hide
- */
-public final class MediaSessionInfo implements Parcelable {
-    private final String mId;
-    private final String mPackageName;
-    private final int mPid;
-
-    /**
-     * @hide
-     */
-    public MediaSessionInfo(String id, String packageName, int pid) {
-        mId = id;
-        mPackageName = packageName;
-        mPid = pid;
-    }
-
-    private MediaSessionInfo(Parcel in) {
-        mId = in.readString();
-        mPackageName = in.readString();
-        mPid = in.readInt();
-    }
-
-    /**
-     * Get the package name of the owner of this session.
-     *
-     * @return The owner's package name
-     */
-    public String getPackageName() {
-        return mPackageName;
-    }
-
-    /**
-     * Get the unique id for this session.
-     *
-     * @return The id for the session.
-     */
-    public String getId() {
-        return mId;
-    }
-
-    public int getPid() {
-        return mPid;
-    }
-
-    @Override
-    public String toString() {
-        return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + ", pid=" + mPid + "}";
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mId);
-        dest.writeString(mPackageName);
-        dest.writeInt(mPid);
-    }
-
-    public static final Parcelable.Creator<MediaSessionInfo> CREATOR
-            = new Parcelable.Creator<MediaSessionInfo>() {
-        @Override
-        public MediaSessionInfo createFromParcel(Parcel in) {
-            return new MediaSessionInfo(in);
-        }
-
-        @Override
-        public MediaSessionInfo[] newArray(int size) {
-            return new MediaSessionInfo[size];
-        }
-    };
-}
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index da1a6ed..f075ded 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -21,6 +21,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
 import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.MediaMetadataEditor;
@@ -73,19 +77,23 @@
         return sInstance;
     }
 
-    public static Bundle getOldMetadata(MediaMetadata metadata) {
+    public static Bundle getOldMetadata(MediaMetadata metadata, int artworkWidth,
+            int artworkHeight) {
+        boolean includeArtwork = artworkWidth != -1 && artworkHeight != -1;
         Bundle oldMetadata = new Bundle();
         if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) {
             oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUM),
                     metadata.getString(MediaMetadata.METADATA_KEY_ALBUM));
         }
-        if (metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) {
+        if (includeArtwork && metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) {
+            Bitmap art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
             oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
-                    metadata.getBitmap(MediaMetadata.METADATA_KEY_ART));
-        } else if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) {
+                    scaleBitmapIfTooBig(art, artworkWidth, artworkHeight));
+        } else if (includeArtwork && metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) {
             // Fall back to album art if the track art wasn't available
+            Bitmap art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
             oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
-                    metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART));
+                    scaleBitmapIfTooBig(art, artworkWidth, artworkHeight));
         }
         if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ARTIST)) {
             oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST),
@@ -296,7 +304,7 @@
 
         holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context);
         holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler);
-        holder.mSession.setMediaButtonReceiver(mbrComponent);
+        holder.mSession.setMediaButtonReceiver(pi);
         if (DEBUG) {
             Log.d(TAG, "addMediaButtonListener added " + pi);
         }
@@ -322,11 +330,46 @@
         }
     }
 
+    /**
+     * Scale a bitmap to fit the smallest dimension by uniformly scaling the
+     * incoming bitmap. If the bitmap fits, then do nothing and return the
+     * original.
+     *
+     * @param bitmap
+     * @param maxWidth
+     * @param maxHeight
+     * @return
+     */
+    private static Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
+        if (bitmap != null) {
+            final int width = bitmap.getWidth();
+            final int height = bitmap.getHeight();
+            if (width > maxWidth || height > maxHeight) {
+                float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
+                int newWidth = Math.round(scale * width);
+                int newHeight = Math.round(scale * height);
+                Bitmap.Config newConfig = bitmap.getConfig();
+                if (newConfig == null) {
+                    newConfig = Bitmap.Config.ARGB_8888;
+                }
+                Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig);
+                Canvas canvas = new Canvas(outBitmap);
+                Paint paint = new Paint();
+                paint.setAntiAlias(true);
+                paint.setFilterBitmap(true);
+                canvas.drawBitmap(bitmap, null,
+                        new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
+                bitmap = outBitmap;
+            }
+        }
+        return bitmap;
+    }
+
     private SessionHolder getHolder(PendingIntent pi, boolean createIfMissing) {
         SessionHolder holder = mSessions.get(pi);
         if (holder == null && createIfMissing) {
             MediaSession session;
-            session = new MediaSession(mContext, TAG);
+            session = new MediaSession(mContext, TAG + "-" + pi.getCreatorPackage());
             session.setActive(true);
             holder = new SessionHolder(session, pi);
             mSessions.put(pi, holder);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 824b397..84983b9 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -116,7 +116,7 @@
             List<IBinder> binders = mService.getSessions(notificationListener, userId);
             int size = binders.size();
             for (int i = 0; i < size; i++) {
-                MediaController controller = new MediaController(ISessionController.Stub
+                MediaController controller = new MediaController(mContext, ISessionController.Stub
                         .asInterface(binders.get(i)));
                 controllers.add(controller);
             }
@@ -175,7 +175,6 @@
      * Stop receiving active sessions updates on the specified listener.
      *
      * @param listener The listener to remove.
-     * @hide
      */
     public void removeActiveSessionsListener(@NonNull SessionListener listener) {
         if (listener == null) {
@@ -253,6 +252,11 @@
      * using {@link #addActiveSessionsListener}.
      */
     public static abstract class SessionListener {
+        private final Context mContext;
+
+        public SessionListener(Context context) {
+            mContext = context;
+        }
         /**
          * Called when the list of active sessions has changed. This can be due
          * to a session being added or removed or the order of sessions
@@ -271,7 +275,7 @@
                 ArrayList<MediaController> controllers = new ArrayList<MediaController>();
                 int size = tokens.size();
                 for (int i = 0; i < size; i++) {
-                    controllers.add(new MediaController(tokens.get(i)));
+                    controllers.add(new MediaController(mContext, tokens.get(i)));
                 }
                 SessionListener.this.onActiveSessionsChanged(controllers);
             }
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index f7e7176..65bd677 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -15,10 +15,17 @@
  */
 package android.media.session;
 
+import android.annotation.DrawableRes;
 import android.media.RemoteControlClient;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Playback state for a {@link MediaSession}. This includes a state like
@@ -26,116 +33,140 @@
  * and the current control capabilities.
  */
 public final class PlaybackState implements Parcelable {
+    private static final String TAG = "PlaybackState";
+
     /**
      * Indicates this performer supports the stop command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_STOP = 1 << 0;
 
     /**
      * Indicates this performer supports the pause command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_PAUSE = 1 << 1;
 
     /**
      * Indicates this performer supports the play command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_PLAY = 1 << 2;
 
     /**
      * Indicates this performer supports the rewind command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_REWIND = 1 << 3;
 
     /**
      * Indicates this performer supports the previous command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
 
     /**
      * Indicates this performer supports the next command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
 
     /**
      * Indicates this performer supports the fast forward command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_FAST_FORWARD = 1 << 6;
 
     /**
      * Indicates this performer supports the set rating command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_SET_RATING = 1 << 7;
 
     /**
      * Indicates this performer supports the seek to command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_SEEK_TO = 1 << 8;
 
     /**
      * Indicates this performer supports the play/pause toggle command.
      *
-     * @see #setActions
+     * @see Builder#setActions(long)
      */
     public static final long ACTION_PLAY_PAUSE = 1 << 9;
 
     /**
+     * Indicates this performer supports the play from uri command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PLAY_URI = 1 << 10;
+
+    /**
+     * Indicates this performer supports the play from search command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
+
+    /**
+     * Indicates this performer supports the skip to track command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SKIP_TO_TRACK = 1 << 12;
+
+    /**
      * This is the default playback state and indicates that no media has been
      * added yet, or the performer has been reset and has no content to play.
      *
-     * @see #setState
+     * @see Builder#setState(int, long, float)
+     * @see Builder#setState(int, long, float, long)
      */
     public final static int STATE_NONE = 0;
 
     /**
      * State indicating this item is currently stopped.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_STOPPED = 1;
 
     /**
      * State indicating this item is currently paused.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_PAUSED = 2;
 
     /**
      * State indicating this item is currently playing.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_PLAYING = 3;
 
     /**
      * State indicating this item is currently fast forwarding.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_FAST_FORWARDING = 4;
 
     /**
      * State indicating this item is currently rewinding.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_REWINDING = 5;
 
@@ -143,7 +174,7 @@
      * State indicating this item is currently buffering and will begin playing
      * when enough data has buffered.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_BUFFERING = 6;
 
@@ -151,7 +182,7 @@
      * State indicating this item is currently in an error state. The error
      * message should also be set when entering this state.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_ERROR = 7;
 
@@ -161,21 +192,21 @@
      * state when the connection finishes or enter {@link #STATE_NONE}.
      * If the connection failed {@link #STATE_ERROR} should be used.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_CONNECTING = 8;
 
     /**
      * State indicating the player is currently skipping to the previous item.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
 
     /**
      * State indicating the player is currently skipping to the next item.
      *
-     * @see #setState
+     * @see Builder#setState
      */
     public final static int STATE_SKIPPING_TO_NEXT = 10;
 
@@ -189,17 +220,23 @@
     private final long mBufferPosition;
     private final float mSpeed;
     private final long mActions;
+    private List<PlaybackState.CustomAction> mCustomActions;
     private final CharSequence mErrorMessage;
     private final long mUpdateTime;
+    private final long mActiveTrackId;
 
     private PlaybackState(int state, long position, long updateTime, float speed,
-            long bufferPosition, long actions, CharSequence error) {
+            long bufferPosition, long transportControls,
+            List<PlaybackState.CustomAction> customActions, long activeTrackId,
+            CharSequence error) {
         mState = state;
         mPosition = position;
         mSpeed = speed;
         mUpdateTime = updateTime;
         mBufferPosition = bufferPosition;
-        mActions = actions;
+        mActions = transportControls;
+        mCustomActions = new ArrayList<>(customActions);
+        mActiveTrackId = activeTrackId;
         mErrorMessage = error;
     }
 
@@ -210,6 +247,8 @@
         mUpdateTime = in.readLong();
         mBufferPosition = in.readLong();
         mActions = in.readLong();
+        mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
+        mActiveTrackId = in.readLong();
         mErrorMessage = in.readCharSequence();
 
     }
@@ -223,6 +262,8 @@
         bob.append(", speed=").append(mSpeed);
         bob.append(", updated=").append(mUpdateTime);
         bob.append(", actions=").append(mActions);
+        bob.append(", custom actions=").append(mCustomActions);
+        bob.append(", active track id=").append(mActiveTrackId);
         bob.append(", error=").append(mErrorMessage);
         bob.append("}");
         return bob.toString();
@@ -241,6 +282,8 @@
         dest.writeLong(mUpdateTime);
         dest.writeLong(mBufferPosition);
         dest.writeLong(mActions);
+        dest.writeTypedList(mCustomActions);
+        dest.writeLong(mActiveTrackId);
         dest.writeCharSequence(mErrorMessage);
     }
 
@@ -306,6 +349,13 @@
     }
 
     /**
+     * Get the list of custom actions.
+     */
+    public List<PlaybackState.CustomAction> getCustomActions() {
+        return mCustomActions;
+    }
+
+    /**
      * Get a user readable error message. This should be set when the state is
      * {@link PlaybackState#STATE_ERROR}.
      */
@@ -492,9 +542,173 @@
     };
 
     /**
+     * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of
+     * the standard transport controls by exposing app specific actions to
+     * {@link MediaController MediaControllers}.
+     */
+    public static final class CustomAction implements Parcelable {
+        private final String mAction;
+        private final CharSequence mName;
+        private final int mIcon;
+        private final Bundle mExtras;
+
+        /**
+         * Use {@link PlaybackState.CustomAction.Builder#build()}.
+         */
+        private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
+            mAction = action;
+            mName = name;
+            mIcon = icon;
+            mExtras = extras;
+        }
+
+        private CustomAction(Parcel in) {
+            mAction = in.readString();
+            mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            mIcon = in.readInt();
+            mExtras = in.readBundle();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(mAction);
+            TextUtils.writeToParcel(mName, dest, flags);
+            dest.writeInt(mIcon);
+            dest.writeBundle(mExtras);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<PlaybackState.CustomAction> CREATOR
+                = new Parcelable.Creator<PlaybackState.CustomAction>() {
+
+            @Override
+            public PlaybackState.CustomAction createFromParcel(Parcel p) {
+                return new PlaybackState.CustomAction(p);
+            }
+
+            @Override
+            public PlaybackState.CustomAction[] newArray(int size) {
+                return new PlaybackState.CustomAction[size];
+            }
+        };
+
+        /**
+         * Returns the action of the {@link CustomAction}.
+         *
+         * @return The action of the {@link CustomAction}.
+         */
+        public String getAction() {
+            return mAction;
+        }
+
+        /**
+         * Returns the display name of this action. e.g. "Favorite"
+         *
+         * @return The display name of this {@link CustomAction}.
+         */
+        public CharSequence getName() {
+            return mName;
+        }
+
+        /**
+         * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package.
+         *
+         * @return The resource id of the icon in the {@link MediaSession MediaSession's} package.
+         */
+        public int getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * Returns extras which provide additional application-specific information about the
+         * action, or null if none. These arguments are meant to be consumed by a
+         * {@link MediaController} if it knows how to handle them.
+         *
+         * @return Optional arguments for the {@link CustomAction}.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+
+        @Override
+        public String toString() {
+            return "Action:" +
+                    "mName='" + mName +
+                    ", mIcon=" + mIcon +
+                    ", mExtras=" + mExtras;
+        }
+
+        /**
+         * Builder for {@link CustomAction} objects.
+         */
+        public static final class Builder {
+            private final String mAction;
+            private final CharSequence mName;
+            private final int mIcon;
+            private Bundle mExtras;
+
+            /**
+             * Creates a {@link CustomAction} builder with the id, name, and icon set.
+             *
+             * @param action The action of the {@link CustomAction}.
+             * @param name The display name of the {@link CustomAction}. This name will be displayed
+             *             along side the action if the UI supports it.
+             * @param icon The icon resource id of the {@link CustomAction}. This resource id
+             *             must be in the same package as the {@link MediaSession}. It will be
+             *             displayed with the custom action if the UI supports it.
+             */
+            public Builder(String action, CharSequence name, @DrawableRes int icon) {
+                if (TextUtils.isEmpty(action)) {
+                    throw new IllegalArgumentException(
+                            "You must specify an action to build a CustomAction.");
+                }
+                if (TextUtils.isEmpty(name)) {
+                    throw new IllegalArgumentException(
+                            "You must specify a name to build a CustomAction.");
+                }
+                if (icon == 0) {
+                    throw new IllegalArgumentException(
+                            "You must specify an icon resource id to build a CustomAction.");
+                }
+                mAction = action;
+                mName = name;
+                mIcon = icon;
+            }
+
+            /**
+             * Set optional extras for the {@link CustomAction}. These extras are meant to be
+             * consumed by a {@link MediaController} if it knows how to handle them.
+             * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions.
+             *
+             * @param extras Optional extras for the {@link CustomAction}.
+             * @return this.
+             */
+            public Builder setExtras(Bundle extras) {
+                mExtras = extras;
+                return this;
+            }
+
+            /**
+             * Build and return the {@link CustomAction} instance with the specified values.
+             *
+             * @return A new {@link CustomAction} instance.
+             */
+            public CustomAction build() {
+                return new CustomAction(mAction, mName, mIcon, mExtras);
+            }
+        }
+    }
+
+    /**
      * Builder for {@link PlaybackState} objects.
      */
     public static final class Builder {
+        private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>();
+
         private int mState;
         private long mPosition;
         private long mBufferPosition;
@@ -502,6 +716,7 @@
         private long mActions;
         private CharSequence mErrorMessage;
         private long mUpdateTime;
+        private long mActiveTrackId = MediaSession.Track.UNKNOWN_ID;
 
         /**
          * Creates an initially empty state builder.
@@ -524,8 +739,12 @@
             mBufferPosition = from.mBufferPosition;
             mSpeed = from.mSpeed;
             mActions = from.mActions;
+            if (from.mCustomActions != null) {
+                mCustomActions.addAll(from.mCustomActions);
+            }
             mErrorMessage = from.mErrorMessage;
             mUpdateTime = from.mUpdateTime;
+            mActiveTrackId = from.mActiveTrackId;
         }
 
         /**
@@ -626,12 +845,52 @@
         }
 
         /**
+         * Add a custom action to the playback state. Actions can be used to expose additional
+         * functionality to {@link MediaController MediaControllers} beyond what is offered by the
+         * standard transport controls.
+         * <p>
+         * e.g. start a radio station based on the current item or skip ahead by 30 seconds.
+         *
+         * @param action An identifier for this action. It will be sent back to the
+         *               {@link MediaSession} through
+         *               {@link
+         *               MediaSession.TransportControlsCallback#onCustomAction(String, Bundle)}.
+         * @param name The display name for the action. If text is shown with the action or used
+         *             for accessibility, this is what should be used.
+         * @param icon The resource action of the icon that should be displayed for the action. The
+         *             resource should be in the package of the {@link MediaSession}.
+         * @return this
+         */
+        public Builder addCustomAction(String action, String name, int icon) {
+            return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null));
+        }
+
+        /**
+         * Add a custom action to the playback state. Actions can be used to expose additional
+         * functionality to {@link MediaController MediaControllers} beyond what is offered by the
+         * standard transport controls.
+         * <p>
+         * An example of an action would be to start a radio station based on the current item
+         * or to skip ahead by 30 seconds.
+         *
+         * @param customAction The custom action to add to the {@link PlaybackState}.
+         * @return this
+         */
+        public Builder addCustomAction(PlaybackState.CustomAction customAction) {
+            if (customAction == null) {
+                throw new IllegalArgumentException(
+                        "You may not add a null CustomAction to PlaybackState.");
+            }
+            mCustomActions.add(customAction);
+            return this;
+        }
+
+        /**
          * Set the current buffer position in ms. This is the farthest playback
          * point that can be reached from the current position using only
          * buffered content.
          *
-         * @param bufferPosition The position in ms that playback is buffered
-         *            to.
+         * @param bufferPosition The position in ms that playback is buffered to.
          * @return this
          */
         public Builder setBufferPosition(long bufferPosition) {
@@ -640,6 +899,18 @@
         }
 
         /**
+         * Set the active track in the play queue by specifying its id.
+         * The default value is {@link MediaSession.Track#UNKNOWN_ID}
+         *
+         * @param id The id of the active track.
+         * @return this
+         */
+        public Builder setActiveTrack(long id) {
+            mActiveTrackId = id;
+            return this;
+        }
+
+        /**
          * Set a user readable error message. This should be set when the state
          * is {@link PlaybackState#STATE_ERROR}.
          *
@@ -652,13 +923,13 @@
         }
 
         /**
-         * Build and return the PlaybackState instance with these values.
+         * Build and return the {@link PlaybackState} instance with these values.
          *
          * @return A new state instance.
          */
         public PlaybackState build() {
             return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferPosition,
-                    mActions, mErrorMessage);
+                    mActions, mCustomActions, mActiveTrackId, mErrorMessage);
         }
     }
 }
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 8e64693..559ea0c 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -24,6 +24,7 @@
 import android.media.tv.ITvInputManagerCallback;
 import android.media.tv.TvInputHardwareInfo;
 import android.media.tv.TvInputInfo;
+import android.media.tv.TvStreamConfig;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
 import android.os.Bundle;
@@ -43,6 +44,7 @@
     void createSession(in ITvInputClient client, in String inputId, int seq, int userId);
     void releaseSession(in IBinder sessionToken, int userId);
 
+    void setMainSession(in IBinder sessionToken, int userId);
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
     void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
             int userId);
@@ -67,4 +69,9 @@
     ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback,
             in TvInputInfo info, int userId);
     void releaseTvInputHardware(int deviceId, in ITvInputHardware hardware, int userId);
+
+    // For TV input capturing
+    List<TvStreamConfig> getAvailableTvStreamConfigList(in String inputId, int userId);
+    boolean captureFrame(in String inputId, in Surface surface, in TvStreamConfig config,
+            int userId);
 }
diff --git a/media/java/android/media/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl
index df648e7..26a0d20 100644
--- a/media/java/android/media/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -27,4 +27,5 @@
     void addHardwareTvInput(in int deviceID, in TvInputInfo inputInfo);
     void addHdmiCecTvInput(in int logicalAddress, in TvInputInfo inputInfo);
     void removeTvInput(in String inputId);
+    void setWrappedInputId(in String inputId, in String wrappedInputId);
 }
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index c5c1f14..df14ad6 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -29,6 +29,7 @@
 oneway interface ITvInputSession {
     void release();
 
+    void setMainSession(boolean isMainSession);
     void setSurface(in Surface surface);
     void dispatchSurfaceChanged(int format, int width, int height);
     // TODO: Remove this once it becomes irrelevant for applications to handle audio focus. The plan
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index bdc59ac..9fb552c 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -42,18 +42,19 @@
     private static final String TAG = "TvInputSessionWrapper";
 
     private static final int DO_RELEASE = 1;
-    private static final int DO_SET_SURFACE = 2;
-    private static final int DO_DISPATCH_SURFACE_CHANGED = 3;
-    private static final int DO_SET_STREAM_VOLUME = 4;
-    private static final int DO_TUNE = 5;
-    private static final int DO_SET_CAPTION_ENABLED = 6;
-    private static final int DO_SELECT_TRACK = 7;
-    private static final int DO_UNSELECT_TRACK = 8;
-    private static final int DO_APP_PRIVATE_COMMAND = 9;
-    private static final int DO_CREATE_OVERLAY_VIEW = 10;
-    private static final int DO_RELAYOUT_OVERLAY_VIEW = 11;
-    private static final int DO_REMOVE_OVERLAY_VIEW = 12;
-    private static final int DO_REQUEST_UNBLOCK_CONTENT = 13;
+    private static final int DO_SET_MAIN_SESSION = 2;
+    private static final int DO_SET_SURFACE = 3;
+    private static final int DO_DISPATCH_SURFACE_CHANGED = 4;
+    private static final int DO_SET_STREAM_VOLUME = 5;
+    private static final int DO_TUNE = 6;
+    private static final int DO_SET_CAPTION_ENABLED = 7;
+    private static final int DO_SELECT_TRACK = 8;
+    private static final int DO_UNSELECT_TRACK = 9;
+    private static final int DO_APP_PRIVATE_COMMAND = 10;
+    private static final int DO_CREATE_OVERLAY_VIEW = 11;
+    private static final int DO_RELAYOUT_OVERLAY_VIEW = 12;
+    private static final int DO_REMOVE_OVERLAY_VIEW = 13;
+    private static final int DO_REQUEST_UNBLOCK_CONTENT = 14;
 
     private final HandlerCaller mCaller;
 
@@ -91,6 +92,10 @@
                 }
                 return;
             }
+            case DO_SET_MAIN_SESSION: {
+                mTvInputSessionImpl.setMainSession((Boolean) msg.obj);
+                return;
+            }
             case DO_SET_SURFACE: {
                 mTvInputSessionImpl.setSurface((Surface) msg.obj);
                 return;
@@ -142,7 +147,7 @@
                 return;
             }
             case DO_REQUEST_UNBLOCK_CONTENT: {
-                mTvInputSessionImpl.requestUnblockContent((String) msg.obj);
+                mTvInputSessionImpl.unblockContent((String) msg.obj);
                 return;
             }
             default: {
@@ -158,6 +163,11 @@
     }
 
     @Override
+    public void setMainSession(boolean isMain) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_MAIN_SESSION, isMain));
+    }
+
+    @Override
     public void setSurface(Surface surface) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_SURFACE, surface));
     }
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index d2071ef..1a43051 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -696,19 +696,6 @@
         public static final String COLUMN_SEARCHABLE = "searchable";
 
         /**
-         * The flag indicating whether this TV channel is scrambled by conditional access or not.
-         * <p>
-         * This is used for indicating that this channel is protected by a conditional access
-         * system. A value of 1 indicates the channel is scrambled and the user is required
-         * to contact the service provider to watch this channel. A value of 0 indicates the channel
-         * is not scrambled. If not specified, this value is set to 0 (not scrambled) by default.
-         * </p><p>
-         * Type: INTEGER (boolean)
-         * </p>
-         */
-        public static final String COLUMN_CONDITIONAL_ACCESS = "conditional_access";
-
-        /**
          * The flag indicating whether this TV channel is locked or not.
          * <p>
          * This is primarily used for alternative parental control to prevent unauthorized users
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 5bed40b..4bb0c53 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -683,6 +683,41 @@
     }
 
     /**
+     * Returns the TvStreamConfig list of the given TV input.
+     *
+     * @param inputId the id of the TV input.
+     * @return List of {@link TvStreamConfig} which is available for capturing
+     *   of the given TV input.
+     * @hide
+     */
+    @SystemApi
+    public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId) {
+        try {
+            return mService.getAvailableTvStreamConfigList(inputId, mUserId);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Take a snapshot of the given TV input into the provided Surface.
+     *
+     * @param inputId the id of the TV input.
+     * @param surface the {@link Surface} to which the snapshot is captured.
+     * @param config the {@link TvStreamConfig} which is used for capturing.
+     * @return true when the {@link Surface} is ready to be captured.
+     * @hide
+     */
+    @SystemApi
+    public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config) {
+        try {
+            return mService.captureFrame(inputId, surface, config, mUserId);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
      * The Session provides the per-session functionality of TV inputs.
      * @hide
      */
@@ -739,6 +774,22 @@
         }
 
         /**
+         * Set this as main session. See {@link TvView#setMainTvView} for about meaning of "main".
+         * @hide
+         */
+        public void setMainSession() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.setMainSession(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
          * Sets the {@link android.view.Surface} for this session.
          *
          * @param surface A {@link android.view.Surface} used to render video.
diff --git a/media/java/android/media/tv/TvInputPassthroughWrapperService.java b/media/java/android/media/tv/TvInputPassthroughWrapperService.java
index 562dc2f..08c802f6 100644
--- a/media/java/android/media/tv/TvInputPassthroughWrapperService.java
+++ b/media/java/android/media/tv/TvInputPassthroughWrapperService.java
@@ -75,6 +75,7 @@
         if (!session.connect(passthroughInputId)) {
             throw new IllegalStateException("WrapperSession cannot be reused.");
         }
+        notifyWrappedInputId(inputId, passthroughInputId);
         return session;
     }
 
@@ -169,7 +170,7 @@
             public void onSessionEvent(TvInputManager.Session session, String eventType,
                     Bundle eventArgs) {
                 if (mSession == session) {
-                    dispatchSessionEvent(eventType, eventArgs);
+                    notifySessionEvent(eventType, eventArgs);
                 }
             }
         };
@@ -187,13 +188,13 @@
 
         /**
          * Called when the underlying pass-through TV input session calls
-         * {@link #dispatchVideoAvailable()}.
+         * {@link #notifyVideoAvailable()}.
          */
         public abstract void onPassthroughVideoAvailable();
 
         /**
          * Called when the underlying pass-through TV input session calls
-         * {@link #dispatchVideoUnavailable(int)}.
+         * {@link #notifyVideoUnavailable(int)}.
          *
          * @param reason The reason why the pass-through TV input stopped the playback.
          */
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index db07b65..6b0a633 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -217,6 +217,21 @@
     }
 
     /**
+     * Notify wrapped TV input ID of current input to TV input framework manager
+     *
+     * @param inputId The TV input ID of {@link TvInputPassthroughWrapperService}
+     * @param wrappedInputId The ID of the wrapped TV input such as external pass-though TV input
+     * @hide
+     */
+    public final void notifyWrappedInputId(String inputId, String wrappedInputId) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = inputId;
+        args.arg2 = wrappedInputId;
+        mHandler.obtainMessage(TvInputService.ServiceHandler.DO_SET_WRAPPED_TV_INPUT_ID,
+                args).sendToTarget();
+    }
+
+    /**
      * Base class for derived classes to implement to provide a TV input session.
      */
     public abstract class Session implements KeyEvent.Callback {
@@ -267,7 +282,7 @@
          * @param eventArgs Optional arguments of the event.
          * @hide
          */
-        public void dispatchSessionEvent(final String eventType, final Bundle eventArgs) {
+        public void notifySessionEvent(final String eventType, final Bundle eventArgs) {
             if (eventType == null) {
                 throw new IllegalArgumentException("eventType should not be null.");
             }
@@ -275,7 +290,7 @@
                 @Override
                 public void run() {
                     try {
-                        if (DEBUG) Log.d(TAG, "dispatchSessionEvent(" + eventType + ")");
+                        if (DEBUG) Log.d(TAG, "notifySessionEvent(" + eventType + ")");
                         mSessionCallback.onSessionEvent(eventType, eventArgs);
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in sending event (event=" + eventType + ")");
@@ -289,15 +304,15 @@
          *
          * @param channelUri The URI of a channel.
          */
-        public void dispatchChannelRetuned(final Uri channelUri) {
+        public void notifyChannelRetuned(final Uri channelUri) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        if (DEBUG) Log.d(TAG, "dispatchChannelRetuned");
+                        if (DEBUG) Log.d(TAG, "notifyChannelRetuned");
                         mSessionCallback.onChannelRetuned(channelUri);
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in dispatchChannelRetuned");
+                        Log.w(TAG, "error in notifyChannelRetuned");
                     }
                 }
             });
@@ -309,7 +324,7 @@
          *
          * @param tracks A list which includes track information.
          */
-        public void dispatchTrackInfoChanged(final List<TvTrackInfo> tracks) {
+        public void notifyTrackInfoChanged(final List<TvTrackInfo> tracks) {
             if (!TvTrackInfo.checkSanity(tracks)) {
                 throw new IllegalArgumentException(
                         "Two or more selected tracks for a track type.");
@@ -318,10 +333,10 @@
                 @Override
                 public void run() {
                     try {
-                        if (DEBUG) Log.d(TAG, "dispatchTrackInfoChanged");
+                        if (DEBUG) Log.d(TAG, "notifyTrackInfoChanged");
                         mSessionCallback.onTrackInfoChanged(tracks);
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in dispatchTrackInfoChanged");
+                        Log.w(TAG, "error in notifyTrackInfoChanged");
                     }
                 }
             });
@@ -331,15 +346,15 @@
          * Informs the application that video is available and the playback of the TV stream has
          * been started.
          */
-        public void dispatchVideoAvailable() {
+        public void notifyVideoAvailable() {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        if (DEBUG) Log.d(TAG, "dispatchVideoAvailable");
+                        if (DEBUG) Log.d(TAG, "notifyVideoAvailable");
                         mSessionCallback.onVideoAvailable();
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in dispatchVideoAvailable");
+                        Log.w(TAG, "error in notifyVideoAvailable");
                     }
                 }
             });
@@ -357,7 +372,7 @@
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
          * </ul>
          */
-        public void dispatchVideoUnavailable(final int reason) {
+        public void notifyVideoUnavailable(final int reason) {
             if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START
                     || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
                 throw new IllegalArgumentException("Unknown reason: " + reason);
@@ -366,10 +381,10 @@
                 @Override
                 public void run() {
                     try {
-                        if (DEBUG) Log.d(TAG, "dispatchVideoUnavailable");
+                        if (DEBUG) Log.d(TAG, "notifyVideoUnavailable");
                         mSessionCallback.onVideoUnavailable(reason);
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in dispatchVideoUnavailable");
+                        Log.w(TAG, "error in notifyVideoUnavailable");
                     }
                 }
             });
@@ -396,18 +411,18 @@
          * reevaluate the current program with the new parental control settings.
          * </p>
          *
-         * @see #dispatchContentBlocked
+         * @see #notifyContentBlocked
          * @see TvParentalControlManager
          */
-        public void dispatchContentAllowed() {
+        public void notifyContentAllowed() {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        if (DEBUG) Log.d(TAG, "dispatchContentAllowed");
+                        if (DEBUG) Log.d(TAG, "notifyContentAllowed");
                         mSessionCallback.onContentAllowed();
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in dispatchContentAllowed");
+                        Log.w(TAG, "error in notifyContentAllowed");
                     }
                 }
             });
@@ -436,18 +451,18 @@
          * </p>
          *
          * @param rating The content rating for the current TV program.
-         * @see #dispatchContentAllowed
+         * @see #notifyContentAllowed
          * @see TvParentalControlManager
          */
-        public void dispatchContentBlocked(final TvContentRating rating) {
+        public void notifyContentBlocked(final TvContentRating rating) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        if (DEBUG) Log.d(TAG, "dispatchContentBlocked");
+                        if (DEBUG) Log.d(TAG, "notifyContentBlocked");
                         mSessionCallback.onContentBlocked(rating.flattenToString());
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in dispatchContentBlocked");
+                        Log.w(TAG, "error in notifyContentBlocked");
                     }
                 }
             });
@@ -459,6 +474,32 @@
         public abstract void onRelease();
 
         /**
+         * Set the current session as the "main" session. See {@link TvView#setMainTvView} for the
+         * meaning of "main".
+         * <p>
+         * This is primarily for HDMI-CEC active source management. TV input service that manages
+         * HDMI-CEC logical device should make sure not only to select the corresponding HDMI
+         * logical device as source device on {@code onSetMainSession(true)}, but also to select
+         * internal device on {@code onSetMainSession(false)}. Also, if surface is set to non-main
+         * session, it needs to select internal device after temporarily selecting corresponding
+         * HDMI logical device for set up.
+         * </p><p>
+         * It is guaranteed that {@code onSetMainSession(true)} for new session is called first,
+         * and {@code onSetMainSession(false)} for old session is called afterwards. This allows
+         * {@code onSetMainSession(false)} to be no-op when TV input service knows that the next
+         * main session corresponds to another HDMI logical device. Practically, this implies that
+         * one TV input service should handle all HDMI port and HDMI-CEC logical devices for smooth
+         * active source transition.
+         * </p>
+         *
+         * @param isMainSession If true, session is main.
+         * @hide
+         */
+        @SystemApi
+        public void onSetMainSession(boolean isMainSession) {
+        }
+
+        /**
          * Sets the {@link Surface} for the current input session on which the TV input renders
          * video.
          *
@@ -488,8 +529,8 @@
         public abstract void onSetStreamVolume(float volume);
 
         /**
-         * Tunes to a given channel. When the video is available, {@link #dispatchVideoAvailable()}
-         * should be called. Also, {@link #dispatchVideoUnavailable(int)} should be called when the
+         * Tunes to a given channel. When the video is available, {@link #notifyVideoAvailable()}
+         * should be called. Also, {@link #notifyVideoUnavailable(int)} should be called when the
          * TV input cannot continue playing the given channel.
          *
          * @param channelUri The URI of the channel.
@@ -521,7 +562,7 @@
          *
          * @param unblockedRating An unblocked content rating
          */
-        public void onRequestUnblockContent(TvContentRating unblockedRating) {
+        public void onUnblockContent(TvContentRating unblockedRating) {
         }
 
         /**
@@ -530,12 +571,12 @@
          * If it is called multiple times on the same type of track (ie. Video, Audio, Text), the
          * track selected previously should be unselected in the implementation of this method.
          * Also, if the select operation was successful, the implementation should call
-         * {@link #dispatchTrackInfoChanged(List)} to report the updated track information.
+         * {@link #notifyTrackInfoChanged(List)} to report the updated track information.
          * </p>
          *
          * @param track The track to be selected.
          * @return {@code true} if the select operation was successful, {@code false} otherwise.
-         * @see #dispatchTrackInfoChanged
+         * @see #notifyTrackInfoChanged
          * @see TvTrackInfo#KEY_IS_SELECTED
          */
         public boolean onSelectTrack(TvTrackInfo track) {
@@ -546,12 +587,12 @@
          * Unselects a given track.
          * <p>
          * If the unselect operation was successful, the implementation should call
-         * {@link #dispatchTrackInfoChanged(List)} to report the updated track information.
+         * {@link #notifyTrackInfoChanged(List)} to report the updated track information.
          * </p>
          *
          * @param track The track to be unselected.
          * @return {@code true} if the unselect operation was successful, {@code false} otherwise.
-         * @see #dispatchTrackInfoChanged
+         * @see #notifyTrackInfoChanged
          * @see TvTrackInfo#KEY_IS_SELECTED
          */
         public boolean onUnselectTrack(TvTrackInfo track) {
@@ -703,12 +744,19 @@
          * session.
          */
         void release() {
+            removeOverlayView(true);
             onRelease();
             if (mSurface != null) {
                 mSurface.release();
                 mSurface = null;
             }
-            removeOverlayView(true);
+        }
+
+        /**
+         * Calls {@link #onSetMainSession}.
+         */
+        void setMainSession(boolean isMainSession) {
+            onSetMainSession(isMainSession);
         }
 
         /**
@@ -773,10 +821,10 @@
         }
 
         /**
-         * Calls {@link #onRequestUnblockContent}.
+         * Calls {@link #onUnblockContent}.
          */
-        void requestUnblockContent(String unblockedRating) {
-            onRequestUnblockContent(TvContentRating.unflattenFromString(unblockedRating));
+        void unblockContent(String unblockedRating) {
+            onUnblockContent(TvContentRating.unflattenFromString(unblockedRating));
             // TODO: Handle failure.
         }
 
@@ -943,6 +991,7 @@
         private static final int DO_REMOVE_HARDWARE_TV_INPUT = 3;
         private static final int DO_ADD_HDMI_CEC_TV_INPUT = 4;
         private static final int DO_REMOVE_HDMI_CEC_TV_INPUT = 5;
+        private static final int DO_SET_WRAPPED_TV_INPUT_ID = 6;
 
         private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
             int n = mCallbacks.beginBroadcast();
@@ -950,7 +999,7 @@
                 try {
                     mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Error while broadcasting: " + e);
+                    Log.e(TAG, "Error while broadcasting.", e);
                 }
             }
             mCallbacks.finishBroadcast();
@@ -963,7 +1012,7 @@
                 try {
                     mCallbacks.getBroadcastItem(i).addHdmiCecTvInput(logicalAddress, inputInfo);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Error while broadcasting: " + e);
+                    Log.e(TAG, "Error while broadcasting.", e);
                 }
             }
             mCallbacks.finishBroadcast();
@@ -975,7 +1024,19 @@
                 try {
                     mCallbacks.getBroadcastItem(i).removeTvInput(inputId);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Error while broadcasting: " + e);
+                    Log.e(TAG, "Error while broadcasting.", e);
+                }
+            }
+            mCallbacks.finishBroadcast();
+        }
+
+        private void broadcastSetWrappedTvInputId(String inputId, String wrappedInputId) {
+            int n = mCallbacks.beginBroadcast();
+            for (int i = 0; i < n; ++i) {
+                try {
+                    mCallbacks.getBroadcastItem(i).setWrappedInputId(inputId, wrappedInputId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error while broadcasting.", e);
                 }
             }
             mCallbacks.finishBroadcast();
@@ -1038,6 +1099,13 @@
                     }
                     return;
                 }
+                case DO_SET_WRAPPED_TV_INPUT_ID: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    String inputId = (String) args.arg1;
+                    String wrappedInputId = (String) args.arg2;
+                    broadcastSetWrappedTvInputId(inputId, wrappedInputId);
+                    return;
+                }
                 default: {
                     Log.w(TAG, "Unhandled message code: " + msg.what);
                     return;
diff --git a/media/java/android/media/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java
index 7f0c92f..243f864 100644
--- a/media/java/android/media/tv/TvStreamConfig.java
+++ b/media/java/android/media/tv/TvStreamConfig.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -23,6 +24,7 @@
 /**
  * @hide
  */
+@SystemApi
 public class TvStreamConfig implements Parcelable {
     static final String TAG = TvStreamConfig.class.getSimpleName();
 
@@ -154,4 +156,4 @@
             return config;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 35dd71e..a5eef0a 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -62,6 +62,9 @@
 
     private static final int VIDEO_SIZE_VALUE_UNKNOWN = 0;
 
+    private static final Object sMainTvViewLock = new Object();
+    private static TvView sMainTvView;
+
     private final Handler mHandler = new Handler();
     private Session mSession;
     private final SurfaceView mSurfaceView;
@@ -161,6 +164,29 @@
     }
 
     /**
+     * Set this as main TvView.
+     * <p>
+     * Main TvView is the TvView which user is watching and interacting mainly.  It is used for
+     * determining internal behavior of hardware TV input devices. For example, this influences
+     * how HDMI-CEC active source will be managed.
+     * </p><p>
+     * First tuned TvView becomes main automatically, and keeps to be main until setMainTvView() is
+     * called for other TvView. Note that main TvView won't be reset even when current main TvView
+     * is removed from view hierarchy.
+     * </p>
+     * @hide
+     */
+    @SystemApi
+    public void setMainTvView() {
+        synchronized (sMainTvViewLock) {
+            sMainTvView = this;
+            if (hasWindowFocus() && mSession != null) {
+                mSession.setMainSession();
+            }
+        }
+    }
+
+    /**
      * Sets the relative stream volume of this session to handle a change of audio focus.
      *
      * @param volume A volume value between 0.0f to 1.0f.
@@ -187,6 +213,11 @@
         if (TextUtils.isEmpty(inputId)) {
             throw new IllegalArgumentException("inputId cannot be null or an empty string");
         }
+        synchronized (sMainTvViewLock) {
+            if (sMainTvView == null) {
+                sMainTvView = this;
+            }
+        }
         if (mSessionCallback != null && mSessionCallback.mInputId.equals(inputId)) {
             if (mSession != null) {
                 mSession.tune(channelUri);
@@ -227,7 +258,7 @@
      * </p>
      *
      * @param unblockedRating A TvContentRating to unblock.
-     * @see TvInputService.Session#dispatchContentBlocked(TvContentRating)
+     * @see TvInputService.Session#notifyContentBlocked(TvContentRating)
      * @hide
      */
     @SystemApi
@@ -413,6 +444,18 @@
     }
 
     @Override
+    public void dispatchWindowFocusChanged(boolean hasFocus) {
+        super.dispatchWindowFocusChanged(hasFocus);
+        // Other app may have shown its own main TvView.
+        // Set main again to regain main session.
+        synchronized (sMainTvViewLock) {
+            if (hasFocus && this == sMainTvView && mSession != null) {
+                mSession.setMainSession();
+            }
+        }
+    }
+
+    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         createSessionOverlayView();
@@ -441,8 +484,8 @@
     }
 
     @Override
-    public void setVisibility(int visibility) {
-        super.setVisibility(visibility);
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
         mSurfaceView.setVisibility(visibility);
         if (visibility == View.VISIBLE) {
             createSessionOverlayView();
@@ -665,6 +708,11 @@
             }
             mSession = session;
             if (session != null) {
+                synchronized (sMainTvViewLock) {
+                    if (hasWindowFocus() && TvView.this == sMainTvView) {
+                        mSession.setMainSession();
+                    }
+                }
                 // mSurface may not be ready yet as soon as starting an application.
                 // In the case, we don't send Session.setSurface(null) unnecessarily.
                 // setSessionSurface will be called in surfaceCreated.
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 35317e1..fa4439d 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -420,8 +420,11 @@
                                 "Width is not multiple of 4 %d", buffer->width);
             LOG_ALWAYS_FATAL_IF(buffer->height % 2,
                                 "Height is not even %d", buffer->height);
+            LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
+                                "stride (%d) should be at least %d",
+                                buffer->stride, buffer->width * 10 / 8);
             pData = buffer->data;
-            dataSize = buffer->width * buffer->height * 10 / 8;
+            dataSize = buffer->stride * buffer->height;
             break;
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
@@ -535,12 +538,15 @@
             rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
             break;
         case HAL_PIXEL_FORMAT_BLOB:
-        case HAL_PIXEL_FORMAT_RAW10:
             // Blob is used for JPEG data, RAW10 is used for 10-bit raw data, they are
             // single plane, row and pixel strides are 0.
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
             rowStride = 0;
             break;
+        case HAL_PIXEL_FORMAT_RAW10:
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            rowStride = buffer->stride;
+            break;
         case HAL_PIXEL_FORMAT_Y8:
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
             LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 04ff098..d033f76 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -90,6 +90,8 @@
     mClass = (jclass)env->NewGlobalRef(clazz);
     mObject = env->NewWeakGlobalRef(thiz);
 
+    cacheJavaObjects(env);
+
     mLooper = new ALooper;
     mLooper->setName("MediaCodec_looper");
 
@@ -105,6 +107,45 @@
     }
 }
 
+void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
+    jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
+    mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
+    CHECK(mByteBufferClass != NULL);
+
+    ScopedLocalRef<jclass> byteOrderClass(
+            env, env->FindClass("java/nio/ByteOrder"));
+    CHECK(byteOrderClass.get() != NULL);
+
+    jmethodID nativeOrderID = env->GetStaticMethodID(
+            byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
+    CHECK(nativeOrderID != NULL);
+
+    jobject nativeByteOrderObj =
+        env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
+    mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
+    CHECK(mNativeByteOrderObj != NULL);
+    env->DeleteLocalRef(nativeByteOrderObj);
+    nativeByteOrderObj = NULL;
+
+    mByteBufferOrderMethodID = env->GetMethodID(
+            mByteBufferClass,
+            "order",
+            "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
+    CHECK(mByteBufferOrderMethodID != NULL);
+
+    mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
+            mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
+    CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
+
+    mByteBufferPositionMethodID = env->GetMethodID(
+            mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
+    CHECK(mByteBufferPositionMethodID != NULL);
+
+    mByteBufferLimitMethodID = env->GetMethodID(
+            mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
+    CHECK(mByteBufferLimitMethodID != NULL);
+}
+
 status_t JMediaCodec::initCheck() const {
     return mCodec != NULL ? OK : NO_INIT;
 }
@@ -148,6 +189,19 @@
     mObject = NULL;
     env->DeleteGlobalRef(mClass);
     mClass = NULL;
+    deleteJavaObjects(env);
+}
+
+void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
+    env->DeleteGlobalRef(mByteBufferClass);
+    mByteBufferClass = NULL;
+    env->DeleteGlobalRef(mNativeByteOrderObj);
+    mNativeByteOrderObj = NULL;
+
+    mByteBufferOrderMethodID = NULL;
+    mByteBufferAsReadOnlyBufferMethodID = NULL;
+    mByteBufferPositionMethodID = NULL;
+    mByteBufferLimitMethodID = NULL;
 }
 
 status_t JMediaCodec::setCallback(jobject cb) {
@@ -298,80 +352,69 @@
         return err;
     }
 
-    ScopedLocalRef<jclass> byteBufferClass(
-            env, env->FindClass("java/nio/ByteBuffer"));
-
-    CHECK(byteBufferClass.get() != NULL);
-
-    jmethodID orderID = env->GetMethodID(
-            byteBufferClass.get(),
-            "order",
-            "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
-
-    CHECK(orderID != NULL);
-
-    jmethodID asReadOnlyBufferID = env->GetMethodID(
-            byteBufferClass.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
-
-    CHECK(asReadOnlyBufferID != NULL);
-
-    ScopedLocalRef<jclass> byteOrderClass(
-            env, env->FindClass("java/nio/ByteOrder"));
-
-    CHECK(byteOrderClass.get() != NULL);
-
-    jmethodID nativeOrderID = env->GetStaticMethodID(
-            byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
-    CHECK(nativeOrderID != NULL);
-
-    jobject nativeByteOrderObj =
-        env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
-    CHECK(nativeByteOrderObj != NULL);
-
     *bufArray = (jobjectArray)env->NewObjectArray(
-            buffers.size(), byteBufferClass.get(), NULL);
+            buffers.size(), mByteBufferClass, NULL);
     if (*bufArray == NULL) {
-        env->DeleteLocalRef(nativeByteOrderObj);
         return NO_MEMORY;
     }
 
     for (size_t i = 0; i < buffers.size(); ++i) {
         const sp<ABuffer> &buffer = buffers.itemAt(i);
 
-        // if this is an ABuffer that doesn't actually hold any accessible memory,
-        // use a null ByteBuffer
-        if (buffer->base() == NULL) {
-            continue;
+        jobject byteBuffer = NULL;
+        err = createByteBufferFromABuffer(
+                env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
+        if (err != OK) {
+            return err;
         }
-        jobject byteBuffer =
-            env->NewDirectByteBuffer(
-                buffer->base(),
-                buffer->capacity());
-        if (!input && byteBuffer != NULL) {
-            jobject readOnlyBuffer = env->CallObjectMethod(
-                    byteBuffer, asReadOnlyBufferID);
+        if (byteBuffer != NULL) {
+            env->SetObjectArrayElement(
+                    *bufArray, i, byteBuffer);
+
             env->DeleteLocalRef(byteBuffer);
-            byteBuffer = readOnlyBuffer;
+            byteBuffer = NULL;
         }
-        if (byteBuffer == NULL) {
-            env->DeleteLocalRef(nativeByteOrderObj);
-            return NO_MEMORY;
-        }
-        jobject me = env->CallObjectMethod(
-                byteBuffer, orderID, nativeByteOrderObj);
-        env->DeleteLocalRef(me);
-        me = NULL;
-
-        env->SetObjectArrayElement(
-                *bufArray, i, byteBuffer);
-
-        env->DeleteLocalRef(byteBuffer);
-        byteBuffer = NULL;
     }
 
-    env->DeleteLocalRef(nativeByteOrderObj);
-    nativeByteOrderObj = NULL;
+    return OK;
+}
 
+// static
+status_t JMediaCodec::createByteBufferFromABuffer(
+        JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
+        jobject *buf) const {
+    // if this is an ABuffer that doesn't actually hold any accessible memory,
+    // use a null ByteBuffer
+    *buf = NULL;
+    if (buffer->base() == NULL) {
+        return OK;
+    }
+
+    jobject byteBuffer =
+        env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
+    if (readOnly && byteBuffer != NULL) {
+        jobject readOnlyBuffer = env->CallObjectMethod(
+                byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
+        env->DeleteLocalRef(byteBuffer);
+        byteBuffer = readOnlyBuffer;
+    }
+    if (byteBuffer == NULL) {
+        return NO_MEMORY;
+    }
+    jobject me = env->CallObjectMethod(
+            byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
+    env->DeleteLocalRef(me);
+    me = env->CallObjectMethod(
+            byteBuffer, mByteBufferLimitMethodID,
+            clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
+    env->DeleteLocalRef(me);
+    me = env->CallObjectMethod(
+            byteBuffer, mByteBufferPositionMethodID,
+            clearBuffer ? 0 : buffer->offset());
+    env->DeleteLocalRef(me);
+    me = NULL;
+
+    *buf = byteBuffer;
     return OK;
 }
 
@@ -388,85 +431,8 @@
         return err;
     }
 
-    ScopedLocalRef<jclass> byteBufferClass(
-            env, env->FindClass("java/nio/ByteBuffer"));
-
-    CHECK(byteBufferClass.get() != NULL);
-
-    jmethodID orderID = env->GetMethodID(
-            byteBufferClass.get(),
-            "order",
-            "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
-
-    CHECK(orderID != NULL);
-
-    jmethodID asReadOnlyBufferID = env->GetMethodID(
-            byteBufferClass.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
-
-    CHECK(asReadOnlyBufferID != NULL);
-
-    jmethodID positionID = env->GetMethodID(
-            byteBufferClass.get(), "position", "(I)Ljava/nio/Buffer;");
-
-    CHECK(positionID != NULL);
-
-    jmethodID limitID = env->GetMethodID(
-            byteBufferClass.get(), "limit", "(I)Ljava/nio/Buffer;");
-
-    CHECK(limitID != NULL);
-
-    ScopedLocalRef<jclass> byteOrderClass(
-            env, env->FindClass("java/nio/ByteOrder"));
-
-    CHECK(byteOrderClass.get() != NULL);
-
-    jmethodID nativeOrderID = env->GetStaticMethodID(
-            byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
-    CHECK(nativeOrderID != NULL);
-
-    jobject nativeByteOrderObj =
-        env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
-    CHECK(nativeByteOrderObj != NULL);
-
-    // if this is an ABuffer that doesn't actually hold any accessible memory,
-    // use a null ByteBuffer
-    if (buffer->base() == NULL) {
-        *buf = NULL;
-        return OK;
-    }
-
-    jobject byteBuffer =
-        env->NewDirectByteBuffer(
-            buffer->base(),
-            buffer->capacity());
-    if (!input && byteBuffer != NULL) {
-        jobject readOnlyBuffer = env->CallObjectMethod(
-                byteBuffer, asReadOnlyBufferID);
-        env->DeleteLocalRef(byteBuffer);
-        byteBuffer = readOnlyBuffer;
-    }
-    if (byteBuffer == NULL) {
-        env->DeleteLocalRef(nativeByteOrderObj);
-        return NO_MEMORY;
-    }
-    jobject me = env->CallObjectMethod(
-            byteBuffer, orderID, nativeByteOrderObj);
-    env->DeleteLocalRef(me);
-    me = env->CallObjectMethod(
-            byteBuffer, limitID,
-            input ? buffer->capacity() : (buffer->offset() + buffer->size()));
-    env->DeleteLocalRef(me);
-    me = env->CallObjectMethod(
-            byteBuffer, positionID,
-            input ? 0 : buffer->offset());
-    env->DeleteLocalRef(me);
-    me = NULL;
-
-    env->DeleteLocalRef(nativeByteOrderObj);
-    nativeByteOrderObj = NULL;
-
-    *buf = byteBuffer;
-    return OK;
+    return createByteBufferFromABuffer(
+            env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
 }
 
 status_t JMediaCodec::getImage(
@@ -490,15 +456,80 @@
     }
 
     // check if buffer is an image
-    AString imageData;
-    if (!buffer->meta()->findString("image-data", &imageData)) {
+    sp<ABuffer> imageData;
+    if (!buffer->meta()->findBuffer("image-data", &imageData)) {
         return OK;
     }
 
+    int64_t timestamp = 0;
+    if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
+        timestamp *= 1000; // adjust to ns
+    }
+
+    jobject byteBuffer = NULL;
+    err = createByteBufferFromABuffer(
+            env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
+    if (err != OK) {
+        return OK;
+    }
+
+    jobject infoBuffer = NULL;
+    err = createByteBufferFromABuffer(
+            env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
+    if (err != OK) {
+        env->DeleteLocalRef(byteBuffer);
+        byteBuffer = NULL;
+        return OK;
+    }
+
+    jobject cropRect = NULL;
+    int32_t left, top, right, bottom;
+    if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
+        ScopedLocalRef<jclass> rectClazz(
+                env, env->FindClass("android/graphics/Rect"));
+        CHECK(rectClazz.get() != NULL);
+
+        jmethodID rectConstructID = env->GetMethodID(
+                rectClazz.get(), "<init>", "(IIII)V");
+
+        cropRect = env->NewObject(
+                rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
+    }
+
+    ScopedLocalRef<jclass> imageClazz(
+            env, env->FindClass("android/media/MediaCodec$MediaImage"));
+    CHECK(imageClazz.get() != NULL);
+
+    jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
+            "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
+
+    *buf = env->NewObject(imageClazz.get(), imageConstructID,
+            byteBuffer, infoBuffer,
+            (jboolean)!input /* readOnly */,
+            (jlong)timestamp,
+            (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
+
+    // if MediaImage creation fails, return null
+    if (env->ExceptionCheck()) {
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+        *buf = NULL;
+    }
+
+    if (cropRect != NULL) {
+        env->DeleteLocalRef(cropRect);
+        cropRect = NULL;
+    }
+
+    env->DeleteLocalRef(byteBuffer);
+    byteBuffer = NULL;
+
+    env->DeleteLocalRef(infoBuffer);
+    infoBuffer = NULL;
+
     return OK;
 }
 
-
 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
     AString name;
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index dbccb0f..f84a16a 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -26,6 +26,7 @@
 
 namespace android {
 
+struct ABuffer;
 struct ALooper;
 struct AMessage;
 struct AString;
@@ -121,11 +122,26 @@
     jweak mObject;
     sp<Surface> mSurfaceTextureClient;
 
+    // java objects cached
+    jclass mByteBufferClass;
+    jobject mNativeByteOrderObj;
+    jmethodID mByteBufferOrderMethodID;
+    jmethodID mByteBufferPositionMethodID;
+    jmethodID mByteBufferLimitMethodID;
+    jmethodID mByteBufferAsReadOnlyBufferMethodID;
+
     sp<ALooper> mLooper;
     sp<MediaCodec> mCodec;
 
     sp<AMessage> mCallbackNotification;
 
+    status_t createByteBufferFromABuffer(
+            JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
+            jobject *buf) const;
+
+    void cacheJavaObjects(JNIEnv *env);
+    void deleteJavaObjects(JNIEnv *env);
+
     DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec);
 };
 
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index 1e5c700..007fc14 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -166,7 +166,9 @@
     return ((quality >= CAMCORDER_QUALITY_LIST_START &&
              quality <= CAMCORDER_QUALITY_LIST_END) ||
             (quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
-             quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END));
+             quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END) ||
+             (quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
+              quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END));
 }
 
 static jobject
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png
index 7c4c1a6..54d76c1 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png
index 649985d..1330240 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png
index 791bf6d..6369d18 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png
index 6c32af1..063009d 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png
deleted file mode 100644
index 5bc4e05..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_dark.png
new file mode 100644
index 0000000..bea0eec
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_light.png
new file mode 100644
index 0000000..c4c264e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_alert_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png
deleted file mode 100644
index ffb076c..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_dark.png
new file mode 100644
index 0000000..f7e59a5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_light.png
new file mode 100644
index 0000000..ae50d74
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dialog_info_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
index 179db33..e462727 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
index 8704a78..8ac89b6 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png
deleted file mode 100644
index 465838d..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png
new file mode 100644
index 0000000..3cbff21
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png
new file mode 100644
index 0000000..7c8b540
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
index 434a6e6..8644171 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
index 940d185..0a3a9a6 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
index 35cdc1f..d37d9bf 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png
index 8f3b82c..7ad6c37 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png
index a3df893..bb7e584 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png
new file mode 100644
index 0000000..0f5159b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
index 92225ba..b3e7192 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png
index 55b9b7d..a799a83d 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png
deleted file mode 100644
index 72b611d..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png
new file mode 100644
index 0000000..10c0b99
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png
new file mode 100644
index 0000000..c857519
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
index e08b0e6..b168481 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png
new file mode 100644
index 0000000..4af36b7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
index 0c55e8c..9167c7d 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png
index 880564e..7abe436 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png
index cb60165..737cca7 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png
deleted file mode 100644
index 9a942d2..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png
new file mode 100644
index 0000000..ff8d3aa
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png
new file mode 100644
index 0000000..d422eb7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png
new file mode 100644
index 0000000..3860241
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-hdpi/ic_folder.png
new file mode 100644
index 0000000..3c88982
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png
deleted file mode 100644
index 7c3d69d..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png
deleted file mode 100644
index 8b90094..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png
deleted file mode 100644
index 1e41d7a..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_card_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
index a6e56ea..e9cfdb1 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png
deleted file mode 100644
index b896c55..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_gradient_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-hdpi/ic_hamburger.png
new file mode 100644
index 0000000..4527667
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_hamburger.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png
index c907bf6..f4f9df2 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png
index 1fe7af7..396ce59 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png
index 8a88407..ddf9f9a 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
index 638c812..ab4d176 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png
index 2a007d2..6b01137 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
index 2756327..4eeafad 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png
index b00328b..dca23e6 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png
index 03e0cc7..d52840f 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png
index cf7d2f4..8ff9ea5 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
index 0d4cdc1..3563e97 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
index 20dce0f..2d61dc7 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png
index 3f3b536..3035ac4 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png
index 79bffc9..d1f26a6 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png
index 595c4b9..b0a5f73 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png
index 3700512..9497fb0b 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png
deleted file mode 100644
index 52f1c70..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_dark.png
new file mode 100644
index 0000000..96d23be
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_light.png
new file mode 100644
index 0000000..032fb17
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_download_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png
deleted file mode 100644
index 915e118..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_dark_am.png
new file mode 100644
index 0000000..e2001f7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_light_am.png
new file mode 100644
index 0000000..f2cec4f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_folder_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png
deleted file mode 100644
index 303b7f9..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_dark.png
new file mode 100644
index 0000000..6954b42
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_light.png
new file mode 100644
index 0000000..3ede991
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_recent_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png
deleted file mode 100644
index 2375e17..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_dark.png
new file mode 100644
index 0000000..b43fddd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_light.png
new file mode 100644
index 0000000..f0a8402
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png
index 5c0c87b..665ee0b 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
index 99060cd..6be1f5b 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png
index 09e77afb..821667e4 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png
index f42be13..4e954c4 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png
index b47e306..6ec1234 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png
index 903a041..73e1081 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png
deleted file mode 100644
index 4835d5f..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_dark.png
new file mode 100644
index 0000000..dbe4cb7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_light.png
new file mode 100644
index 0000000..e9ae097
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_alert_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png
deleted file mode 100644
index 2d29442..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_dark.png
new file mode 100644
index 0000000..f8f9eaf
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_light.png
new file mode 100644
index 0000000..f8635fe
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dialog_info_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
index 318dd5b..0d3d5d7 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
index 932995e..f9597f0 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png
deleted file mode 100644
index cb94d99..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png
new file mode 100644
index 0000000..deba408
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png
new file mode 100644
index 0000000..88f0127
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
index 240d7f4..b1323da 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
index 6c6aad6..ff99fd7 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
index 8fc7bea..4af71f3 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png
index 290ad3a..e137ca0 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png
index e5eda72..db55b74 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png
new file mode 100644
index 0000000..3adff71
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
index 00bd478..0a4a841 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png
index a1bd14e..1dce216 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png
deleted file mode 100644
index b81b1e5..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png
new file mode 100644
index 0000000..f061b0c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png
new file mode 100644
index 0000000..fa3d2ea
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
index 3381c42..b558d08 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png
new file mode 100644
index 0000000..efc0b13
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
index 68cc971..655d866 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png
index 2934e5a..a2f9116 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png
index 95565b3..4aa3a0e 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png
deleted file mode 100644
index 3a5b798..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png
new file mode 100644
index 0000000..1b6f00f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png
new file mode 100644
index 0000000..24dad11
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png
new file mode 100644
index 0000000..7f26252
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-mdpi/ic_folder.png
new file mode 100644
index 0000000..17cb056
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png
deleted file mode 100644
index 567a06b..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png
deleted file mode 100644
index 1525572..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png
deleted file mode 100644
index 16c9296..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_card_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
index 6e63b8c..5534c74 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png
deleted file mode 100644
index 1120864..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_gradient_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-mdpi/ic_hamburger.png
new file mode 100644
index 0000000..440c0f6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_hamburger.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png
index fbf5c88..fbd5c21 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png
index ecb4bf2..1939ed7 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png
index 96b01b9..bb06624 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
index ee95809..86b9256 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png
index 7a63828..c7f60c4 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
index 9ab2f78..dc9bbc9 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png
index 2d0ab8a..1f45b99 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png
index cf5575a..db6321d 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png
index 368fbd6..f370056 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
index 2768b1c..86e1cf9 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
index d56db42..ed0ee5d 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png
index 0a0c8f1..6af4222 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png
index 8a724ac..20197f4 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png
index adfacc1..dab578b 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png
index b17de2d..12e873d 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png
deleted file mode 100644
index 4f903df..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_dark.png
new file mode 100644
index 0000000..d3f3e08
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_light.png
new file mode 100644
index 0000000..23663d7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_download_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png
deleted file mode 100644
index 4352d08..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_dark_am.png
new file mode 100644
index 0000000..8d9de3d
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_light_am.png
new file mode 100644
index 0000000..35505fe
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_folder_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png
deleted file mode 100644
index bf9b1b6..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_dark.png
new file mode 100644
index 0000000..67789a3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_light.png
new file mode 100644
index 0000000..6f8d9a5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_recent_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png
deleted file mode 100644
index 6adc2a3..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_dark.png
new file mode 100644
index 0000000..3b945e1
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_light.png
new file mode 100644
index 0000000..7032d5f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png
index d318dba..a4f474b 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
index a7a2b12..c8c9f1a 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png
index 33c8f27..74fdc2b 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png
index ef9641d..6f8f34f 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png
index 9c3d008..d360431 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png
index 4cf4f3f..21319d8 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png
deleted file mode 100644
index 17f9f9e..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_dark.png
new file mode 100644
index 0000000..eeef696
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_light.png
new file mode 100644
index 0000000..0b52ce4a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_alert_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png
deleted file mode 100644
index 2f9cc58..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_dark.png
new file mode 100644
index 0000000..7006326
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_light.png
new file mode 100644
index 0000000..28b69c6
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dialog_info_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
index e67aa8d..8952222 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
index d0e2594..bc833b4 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png
deleted file mode 100644
index 2e66f03..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png
new file mode 100644
index 0000000..c782d0f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png
new file mode 100644
index 0000000..fbc1e24
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
index 64e0d42..de17d0b 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
index a4f70ba..d396745 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
index 4897221c..1627d8e 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png
index 4cec994..a6f91b5 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png
index 5e46b71..cff0ab6 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png
new file mode 100644
index 0000000..884dd58
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
index 977cfd2..9f70fb8 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png
index e05c4b4..7fb5ef6 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png
deleted file mode 100644
index 98d3f79..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png
new file mode 100644
index 0000000..49e4d0a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png
new file mode 100644
index 0000000..09609e3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
index ff2ff14..cdb8471 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png
new file mode 100644
index 0000000..f319929
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
index 2917377..ee8f63c 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png
index 87c6538..faa648d4 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png
index 97c4500..872a67b 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png
deleted file mode 100644
index 1a8e632..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png
new file mode 100644
index 0000000..aaa951b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png
new file mode 100644
index 0000000..1342087
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png
new file mode 100644
index 0000000..8c883ad
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_folder.png
new file mode 100644
index 0000000..0d3f869
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png
deleted file mode 100644
index 8f7f4ab..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png
deleted file mode 100644
index b82ae20..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png
deleted file mode 100644
index edd6266..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_card_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
index c3af9ec..a1c9789 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png
deleted file mode 100644
index 60ce8d5..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_gradient_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_hamburger.png
new file mode 100644
index 0000000..f7a1779
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_hamburger.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png
index c650185..295576c 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png
index 0771ed2..19c19ba 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png
index 91c31e3..22cbd7b 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
index f06b298..bbdee7e 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png
index c3a7eaa..7a050c9 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
index 17e09b3..8ccca63 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png
index 0ab604f..4c87e59 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png
index 5054fc8..d0929cf 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png
index d3d386e..e55b347 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
index f24ca1a..28b7d5c 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
index 82c1a30..1121c43 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png
index 0258312..47b5333 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png
index ccace9d..62ab8fb 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png
index a56940a..f969418 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png
index f6a0af4..204b04d 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png
deleted file mode 100644
index 6c6447e..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_dark.png
new file mode 100644
index 0000000..2460761
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_light.png
new file mode 100644
index 0000000..1de0247
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_download_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png
deleted file mode 100644
index c916e0b..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_dark_am.png
new file mode 100644
index 0000000..f9788b1
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_light_am.png
new file mode 100644
index 0000000..ff307cd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_folder_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png
deleted file mode 100644
index 714f2ee..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_dark.png
new file mode 100644
index 0000000..be89734
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_light.png
new file mode 100644
index 0000000..90d1e15
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_recent_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png
deleted file mode 100644
index 6016c08..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_dark.png
new file mode 100644
index 0000000..f788f23
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_light.png
new file mode 100644
index 0000000..bc2acbe
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png
index b05b9a4..6ccfb76 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
index 1da8196..94a757a 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png
index 06681e3..21272f4 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_breadcrumb_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png
index ac88818..6824bce 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_accept.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png
index 88356c7..81d7816 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_cancel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png
index 75658db..99c3dbb 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_cab_select_item.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png
deleted file mode 100644
index 8bee0dc..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_dark.png
new file mode 100644
index 0000000..a91cd76
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_light.png
new file mode 100644
index 0000000..73e440a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_alert_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png
deleted file mode 100644
index ad6c59b..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_dark.png
new file mode 100644
index 0000000..aff4bc4
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_light.png
new file mode 100644
index 0000000..7e0fa62
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dialog_info_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
index 4c56bd0c..e7151cf 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
index 5f64229..5c10593 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png
deleted file mode 100644
index 48ab9c7..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png
new file mode 100644
index 0000000..e96ed99
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png
new file mode 100644
index 0000000..cac2aaf
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
index 68e619e..1ee0875 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
index 945119a..8d3dabf 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
index bf49d78..c3e21ae 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png
index 5263365..e809fe65 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png
index 77a0fae..5ed0373 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png
new file mode 100644
index 0000000..1a373f3
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
index 30d2c4c..b4308b4 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png
index c098866..b5ba48b 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png
deleted file mode 100644
index 06d8d9c..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png
new file mode 100644
index 0000000..63e4255
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png
new file mode 100644
index 0000000..6237ded
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
index a3b146b..2c0a81e 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png
new file mode 100644
index 0000000..2fba5ed
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
index c09d6ab..3e391ce 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png
index 2170e66..372abc9 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png
index bc4ce79..e535ca3 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png
deleted file mode 100644
index 42d8ec1..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png
new file mode 100644
index 0000000..48b4a72
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png
new file mode 100644
index 0000000..15d6c50
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png
new file mode 100644
index 0000000..9ccf41e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_folder.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_folder.png
new file mode 100644
index 0000000..9bedcd9
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png
deleted file mode 100644
index 7bbaf9d..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png
deleted file mode 100644
index 901af80..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png
deleted file mode 100644
index e21e350..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_card_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
index 86a74cd..10cdd51 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png
deleted file mode 100644
index 988c856..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_gradient_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_hamburger.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_hamburger.png
new file mode 100644
index 0000000..355f61f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_hamburger.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png
index f23e23c..7f483e1 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_copy.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png
index f67c72e..c19988f 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_delete.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png
index 676d0f7..d10bec8 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_disconnect_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
index b17ba1d0..4013b7c 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png
index 58f1381..036127c 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_overflow.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
index eed0eaf..0fef9d0 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png
index 40fb392..af79507 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_search.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png
index b988ab5..db2ef7b 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_settings.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png
index 6ace932..e6befad 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
index 8f19afa..89bf79f 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
index e4c9f8a..7acc684e 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png
index 9e27d63..0bee75a 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_grid.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png
index e4c679a..da13073 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_view_list.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png
index b467962..7196ee5 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_open_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png
index 5f5a86f..6fa2216 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_popout_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png
deleted file mode 100644
index 3b8afc9..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_dark.png
new file mode 100644
index 0000000..067aa655
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_light.png
new file mode 100644
index 0000000..40437a8
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_download_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png
deleted file mode 100644
index 077c851..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_am.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_dark_am.png
new file mode 100644
index 0000000..069d951
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_light_am.png
new file mode 100644
index 0000000..1725025
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_folder_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png
deleted file mode 100644
index a3215f2..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_dark.png
new file mode 100644
index 0000000..d149239
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_light.png
new file mode 100644
index 0000000..9a06663
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_recent_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png
deleted file mode 100644
index 873a553..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_dark.png
new file mode 100644
index 0000000..429f3c5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_light.png
new file mode 100644
index 0000000..bcfe7fd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png
index d213e7c..c31b4dc 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
index db53a01..d852b8ec 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid.xml b/packages/DocumentsUI/res/drawable/grid_protect_background.xml
similarity index 75%
rename from packages/DocumentsUI/res/drawable/item_doc_grid.xml
rename to packages/DocumentsUI/res/drawable/grid_protect_background.xml
index 3f036f7..2e7aadd 100644
--- a/packages/DocumentsUI/res/drawable/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/drawable/grid_protect_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -15,5 +15,10 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_grid_card_background" />
+    <item android:state_enabled="false">
+        <color android:color="#88000000" />
+    </item>
+    <item>
+        <color android:color="#88252525" />
+    </item>
 </selector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio_dark.xml
similarity index 93%
copy from packages/DocumentsUI/res/drawable/ic_doc_audio.xml
copy to packages/DocumentsUI/res/drawable/ic_doc_audio_dark.xml
index c6ccea6..768d409 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_audio_dark.xml
@@ -18,6 +18,6 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_audio_am"
+        android:src="@drawable/ic_doc_audio_dark_am"
         android:autoMirrored="true">
 </bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio_light.xml
similarity index 93%
copy from packages/DocumentsUI/res/drawable/ic_doc_audio.xml
copy to packages/DocumentsUI/res/drawable/ic_doc_audio_light.xml
index c6ccea6..bdb6983 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_audio_light.xml
@@ -18,6 +18,6 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_audio_am"
+        android:src="@drawable/ic_doc_audio_light_am"
         android:autoMirrored="true">
 </bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video.xml b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
deleted file mode 100644
index e196262..0000000
--- a/packages/DocumentsUI/res/drawable/ic_doc_video.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 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.
- */
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_video_am"
-        android:autoMirrored="true">
-</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_video_dark.xml
similarity index 93%
rename from packages/DocumentsUI/res/drawable/ic_doc_audio.xml
rename to packages/DocumentsUI/res/drawable/ic_doc_video_dark.xml
index c6ccea6..4fb82bb 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_video_dark.xml
@@ -18,6 +18,6 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_audio_am"
+        android:src="@drawable/ic_doc_video_dark_am"
         android:autoMirrored="true">
 </bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_video_light.xml
similarity index 93%
copy from packages/DocumentsUI/res/drawable/ic_doc_audio.xml
copy to packages/DocumentsUI/res/drawable/ic_doc_video_light.xml
index c6ccea6..290c3f1a 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_video_light.xml
@@ -18,6 +18,6 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_audio_am"
+        android:src="@drawable/ic_doc_video_light_am"
         android:autoMirrored="true">
 </bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_root_folder.xml b/packages/DocumentsUI/res/drawable/ic_root_folder.xml
deleted file mode 100644
index a3c8f61..0000000
--- a/packages/DocumentsUI/res/drawable/ic_root_folder.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 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.
- */
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_root_folder_am"
-        android:autoMirrored="true">
-</bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_root_folder_dark.xml
similarity index 93%
copy from packages/DocumentsUI/res/drawable/ic_doc_audio.xml
copy to packages/DocumentsUI/res/drawable/ic_root_folder_dark.xml
index c6ccea6..8e29d1d 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_folder_dark.xml
@@ -18,6 +18,6 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_audio_am"
+        android:src="@drawable/ic_root_folder_dark_am"
         android:autoMirrored="true">
 </bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_root_folder_light.xml
similarity index 92%
copy from packages/DocumentsUI/res/drawable/ic_doc_audio.xml
copy to packages/DocumentsUI/res/drawable/ic_root_folder_light.xml
index c6ccea6..a750f1f 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_folder_light.xml
@@ -18,6 +18,6 @@
 -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_doc_audio_am"
+        android:src="@drawable/ic_root_folder_light_am"
         android:autoMirrored="true">
 </bitmap>
\ No newline at end of file
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid.xml b/packages/DocumentsUI/res/drawable/item_activated.xml
similarity index 71%
copy from packages/DocumentsUI/res/drawable/item_doc_grid.xml
copy to packages/DocumentsUI/res/drawable/item_activated.xml
index 3f036f7..6ffefdb 100644
--- a/packages/DocumentsUI/res/drawable/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/drawable/item_activated.xml
@@ -15,5 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_grid_card_background" />
+    <item android:state_focused="true" android:state_activated="true" android:drawable="@color/accent_item_activated" />
+    <item android:state_focused="false" android:state_activated="true" android:drawable="@color/accent_item_activated" />
+    <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/packages/DocumentsUI/res/drawable/item_background.xml b/packages/DocumentsUI/res/drawable/item_background.xml
deleted file mode 100644
index ec9be6d..0000000
--- a/packages/DocumentsUI/res/drawable/item_background.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
-
-    <item android:state_focused="true"   android:state_activated="true" android:drawable="@drawable/ic_grid_card_focused" />
-    <item android:state_focused="false"  android:state_activated="true" android:drawable="@drawable/ic_grid_card_focused" />
-
-    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/ic_grid_card_pressed" />
-    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/ic_grid_card_pressed" />
-    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/ic_grid_card_pressed" />
-    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/ic_grid_card_pressed" />
-    <item android:state_focused="true"                                                             android:drawable="@drawable/ic_grid_card_pressed" />
-
-    <item android:drawable="@android:color/transparent" />
-
-</selector>
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
index adbb9da..5f1e432 100644
--- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -14,103 +14,111 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/item_background"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
-    android:gravity="center_vertical"
-    android:orientation="horizontal"
-    android:baselineAligned="false">
+    android:foreground="@drawable/item_activated">
 
-    <FrameLayout
-        android:id="@android:id/icon"
-        android:layout_width="@dimen/icon_size"
-        android:layout_height="@dimen/icon_size"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="20dp">
-
-        <ImageView
-            android:id="@+id/icon_mime"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:scaleType="centerInside"
-            android:contentDescription="@null" />
-
-        <ImageView
-            android:id="@+id/icon_thumb"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:scaleType="centerCrop"
-            android:contentDescription="@null" />
-
-    </FrameLayout>
-
-    <!-- This is the one special case where we want baseline alignment! -->
     <LinearLayout
-        android:layout_width="0dp"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:orientation="horizontal">
+        android:minHeight="@dimen/list_item_height"
+        android:paddingStart="@dimen/list_item_padding"
+        android:paddingEnd="@dimen/list_item_padding"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:baselineAligned="false">
 
-        <TextView
-            android:id="@android:id/title"
+        <FrameLayout
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/icon_size"
+            android:layout_height="@dimen/icon_size"
+            android:layout_marginStart="0dp"
+            android:layout_marginEnd="16dp">
+
+            <ImageView
+                android:id="@+id/icon_mime"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:scaleType="centerInside"
+                android:contentDescription="@null" />
+
+            <ImageView
+                android:id="@+id/icon_thumb"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="centerCrop"
+                android:contentDescription="@null" />
+
+        </FrameLayout>
+
+        <!-- This is the one special case where we want baseline alignment! -->
+        <LinearLayout
             android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:layout_weight="0.5"
-            android:layout_marginEnd="12dp"
-            android:singleLine="true"
-            android:ellipsize="middle"
-            android:textAlignment="viewStart"
-            style="@style/TextAppearance.Medium" />
+            android:layout_weight="1"
+            android:orientation="horizontal">
 
-        <ImageView
-            android:id="@android:id/icon1"
-            android:layout_width="@dimen/root_icon_size"
-            android:layout_height="@dimen/root_icon_size"
-            android:layout_marginEnd="8dp"
-            android:scaleType="centerInside"
-            android:contentDescription="@null" />
+            <TextView
+                android:id="@android:id/title"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.5"
+                android:layout_marginEnd="12dp"
+                android:singleLine="true"
+                android:ellipsize="middle"
+                android:textAlignment="viewStart"
+                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                android:textColor="?android:attr/textColorPrimary" />
 
-        <TextView
-            android:id="@android:id/summary"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="0.25"
-            android:layout_marginEnd="12dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:textAlignment="viewStart"
-            style="@style/TextAppearance.Small" />
+            <ImageView
+                android:id="@android:id/icon1"
+                android:layout_width="@dimen/root_icon_size"
+                android:layout_height="@dimen/root_icon_size"
+                android:layout_marginEnd="8dp"
+                android:scaleType="centerInside"
+                android:contentDescription="@null" />
 
-        <TextView
-            android:id="@+id/size"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="0.125"
-            android:layout_marginEnd="12dp"
-            android:minWidth="70dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:textAlignment="viewEnd"
-            style="@style/TextAppearance.Small" />
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.25"
+                android:layout_marginEnd="12dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:textAlignment="viewStart"
+                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textColor="?android:attr/textColorSecondary" />
 
-        <TextView
-            android:id="@+id/date"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="0.125"
-            android:layout_marginEnd="12dp"
-            android:minWidth="70dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:textAlignment="viewEnd"
-            style="@style/TextAppearance.Small" />
+            <TextView
+                android:id="@+id/size"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.125"
+                android:layout_marginEnd="12dp"
+                android:minWidth="70dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:textAlignment="viewEnd"
+                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textColor="?android:attr/textColorSecondary" />
+
+            <TextView
+                android:id="@+id/date"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.125"
+                android:layout_marginEnd="12dp"
+                android:minWidth="70dp"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:textAlignment="viewEnd"
+                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textColor="?android:attr/textColorSecondary" />
+
+        </LinearLayout>
 
     </LinearLayout>
 
-</LinearLayout>
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 77cdc3b..09b50c0 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -31,8 +31,7 @@
     <ListView
         android:id="@+id/list"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:listSelector="@android:color/transparent" />
+        android:layout_height="match_parent" />
 
     <GridView
         android:id="@+id/grid"
@@ -40,11 +39,13 @@
         android:layout_height="match_parent"
         android:paddingStart="@dimen/grid_padding_horiz"
         android:paddingEnd="@dimen/grid_padding_horiz"
-        android:paddingTop="@dimen/grid_padding"
-        android:paddingBottom="@dimen/grid_padding"
+        android:paddingTop="@dimen/grid_padding_vert"
+        android:paddingBottom="@dimen/grid_padding_vert"
+        android:horizontalSpacing="@dimen/grid_item_padding"
+        android:verticalSpacing="@dimen/grid_item_padding"
         android:clipToPadding="false"
         android:scrollbarStyle="outsideOverlay"
-        android:listSelector="@android:color/transparent"
+        android:drawSelectorOnTop="true"
         android:visibility="gone" />
 
 </com.android.documentsui.DirectoryView>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 3aef1cd..0fc606d 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -16,110 +16,111 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/grid_height"
-    android:background="@drawable/item_doc_grid"
-    android:foreground="@drawable/item_background">
+    android:layout_height="@dimen/grid_item_height"
+    android:orientation="vertical"
+    android:background="@color/grid_item_background"
+    android:foreground="@drawable/item_activated">
+
+    <ImageView
+        android:id="@+id/icon_thumb"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="centerCrop"
+        android:contentDescription="@null" />
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingBottom="6dp"
         android:orientation="vertical">
 
-        <FrameLayout
+        <ImageView
+            android:id="@+id/icon_mime"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"
-            android:layout_marginBottom="6dp"
-            android:background="#fff"
-            android:foreground="@drawable/ic_grid_gradient_bg"
-            android:foregroundGravity="fill">
-
-            <ImageView
-                android:id="@+id/icon_mime"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:scaleType="centerInside"
-                android:contentDescription="@null" />
-
-            <ImageView
-                android:id="@+id/icon_thumb"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:scaleType="centerCrop"
-                android:contentDescription="@null" />
-
-        </FrameLayout>
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
 
         <LinearLayout
-            android:id="@+id/line1"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:baselineAligned="false"
+            android:background="@drawable/grid_protect_background"
+            android:orientation="vertical"
             android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp">
 
-            <TextView
-                android:id="@android:id/title"
-                android:layout_width="0dp"
+            <LinearLayout
+                android:id="@+id/line1"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:singleLine="true"
-                android:ellipsize="middle"
-                android:textAlignment="viewStart"
-                style="@style/TextAppearance.Medium" />
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:baselineAligned="false">
 
-            <ImageView
-                android:id="@android:id/icon1"
-                android:layout_width="@dimen/root_icon_size"
-                android:layout_height="@dimen/root_icon_size"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:contentDescription="@null" />
+                <TextView
+                    android:id="@android:id/title"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:singleLine="true"
+                    android:ellipsize="middle"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                    android:textColor="?android:attr/textColorPrimaryInverse" />
 
-        </LinearLayout>
+                <ImageView
+                    android:id="@android:id/icon1"
+                    android:layout_width="@dimen/root_icon_size"
+                    android:layout_height="@dimen/root_icon_size"
+                    android:layout_marginStart="8dp"
+                    android:scaleType="centerInside"
+                    android:contentDescription="@null" />
 
-        <LinearLayout
-            android:id="@+id/line2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:baselineAligned="false"
-            android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+            </LinearLayout>
 
-            <TextView
-                android:id="@+id/date"
-                android:layout_width="0dp"
+            <LinearLayout
+                android:id="@+id/line2"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_weight="0.5"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:textAlignment="viewStart"
-                style="@style/TextAppearance.Small" />
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:baselineAligned="false">
 
-            <TextView
-                android:id="@+id/size"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="0.5"
-                android:layout_marginStart="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:textAlignment="viewStart"
-                style="@style/TextAppearance.Small" />
+                <TextView
+                    android:id="@+id/date"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0.5"
+                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@android:style/TextAppearance.Material.Caption"
+                    android:textColor="?android:attr/textColorPrimaryInverse" />
 
-            <ImageView
-                android:id="@android:id/icon2"
-                android:layout_width="@dimen/root_icon_size"
-                android:layout_height="@dimen/root_icon_size"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:contentDescription="@null"
-                android:visibility="gone" />
+                <TextView
+                    android:id="@+id/size"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0.5"
+                    android:layout_marginStart="8dp"
+                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@android:style/TextAppearance.Material.Caption"
+                    android:textColor="?android:attr/textColorPrimaryInverse" />
+
+                <ImageView
+                    android:id="@android:id/icon2"
+                    android:layout_width="@dimen/root_icon_size"
+                    android:layout_height="@dimen/root_icon_size"
+                    android:layout_marginStart="8dp"
+                    android:scaleType="centerInside"
+                    android:contentDescription="@null"
+                    android:visibility="gone" />
+
+            </LinearLayout>
 
         </LinearLayout>
 
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index e3a0ddd..50ed2d6 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -14,114 +14,121 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/item_background"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
-    android:gravity="center_vertical"
-    android:orientation="horizontal"
-    android:baselineAligned="false">
-
-    <FrameLayout
-        android:id="@android:id/icon"
-        android:layout_width="@dimen/icon_size"
-        android:layout_height="@dimen/icon_size"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="20dp">
-
-        <ImageView
-            android:id="@+id/icon_mime"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:scaleType="centerInside"
-            android:contentDescription="@null" />
-
-        <ImageView
-            android:id="@+id/icon_thumb"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:scaleType="centerCrop"
-            android:contentDescription="@null" />
-
-    </FrameLayout>
+    android:foreground="@drawable/item_activated">
 
     <LinearLayout
-        android:layout_width="0dp"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:orientation="vertical">
+        android:minHeight="@dimen/list_item_height"
+        android:paddingStart="@dimen/list_item_padding"
+        android:paddingEnd="@dimen/list_item_padding"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:baselineAligned="false">
 
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:baselineAligned="false">
-
-            <TextView
-                android:id="@android:id/title"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:singleLine="true"
-                android:ellipsize="middle"
-                android:textAlignment="viewStart"
-                style="@style/TextAppearance.Medium" />
+        <FrameLayout
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/icon_size"
+            android:layout_height="@dimen/icon_size"
+            android:layout_marginEnd="16dp">
 
             <ImageView
-                android:id="@android:id/icon1"
-                android:layout_width="@dimen/root_icon_size"
-                android:layout_height="@dimen/root_icon_size"
-                android:layout_marginStart="8dp"
+                android:id="@+id/icon_mime"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
                 android:scaleType="centerInside"
                 android:contentDescription="@null" />
 
-        </LinearLayout>
+            <ImageView
+                android:id="@+id/icon_thumb"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="centerCrop"
+                android:contentDescription="@null" />
+
+        </FrameLayout>
 
         <LinearLayout
-            android:id="@+id/line2"
-            android:layout_width="match_parent"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:baselineAligned="false">
+            android:layout_weight="1"
+            android:orientation="vertical">
 
-            <TextView
-                android:id="@+id/date"
-                android:layout_width="90dp"
+            <LinearLayout
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:textAlignment="viewStart"
-                style="@style/TextAppearance.Small" />
+                android:orientation="horizontal"
+                android:baselineAligned="false">
 
-            <TextView
-                android:id="@+id/size"
-                android:layout_width="90dp"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:textAlignment="viewStart"
-                style="@style/TextAppearance.Small" />
+                <TextView
+                    android:id="@android:id/title"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:singleLine="true"
+                    android:ellipsize="middle"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                    android:textColor="?android:attr/textColorPrimary" />
 
-            <TextView
-                android:id="@android:id/summary"
-                android:layout_width="0dp"
+                <ImageView
+                    android:id="@android:id/icon1"
+                    android:layout_width="@dimen/root_icon_size"
+                    android:layout_height="@dimen/root_icon_size"
+                    android:layout_marginStart="8dp"
+                    android:scaleType="centerInside"
+                    android:contentDescription="@null" />
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:id="@+id/line2"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_marginStart="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:textAlignment="viewStart"
-                style="@style/TextAppearance.Small" />
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:baselineAligned="false">
+
+                <TextView
+                    android:id="@+id/date"
+                    android:layout_width="90dp"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textColor="?android:attr/textColorSecondary" />
+
+                <TextView
+                    android:id="@+id/size"
+                    android:layout_width="90dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="8dp"
+                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textColor="?android:attr/textColorSecondary" />
+
+                <TextView
+                    android:id="@android:id/summary"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:layout_marginStart="8dp"
+                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textColor="?android:attr/textColorSecondary" />
+
+            </LinearLayout>
 
         </LinearLayout>
 
     </LinearLayout>
 
-</LinearLayout>
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml
index 0bf6137..005a111 100644
--- a/packages/DocumentsUI/res/layout/item_loading_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml
@@ -17,11 +17,6 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/grid_height"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
     android:orientation="horizontal">
 
     <ProgressBar
diff --git a/packages/DocumentsUI/res/layout/item_loading_list.xml b/packages/DocumentsUI/res/layout/item_loading_list.xml
index cdcd01d..6f214ed 100644
--- a/packages/DocumentsUI/res/layout/item_loading_list.xml
+++ b/packages/DocumentsUI/res/layout/item_loading_list.xml
@@ -17,11 +17,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp">
+    android:minHeight="@dimen/list_item_height">
 
     <ProgressBar
         android:layout_width="wrap_content"
diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml
index b3bdd28..385563d 100644
--- a/packages/DocumentsUI/res/layout/item_message_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_message_grid.xml
@@ -17,11 +17,10 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/grid_height"
-    android:paddingTop="?android:attr/listPreferredItemPaddingStart"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
-    android:foreground="@drawable/item_background">
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -42,9 +41,10 @@
             android:gravity="center"
             android:maxLines="4"
             android:ellipsize="end"
-            android:paddingTop="6dp"
-            android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textAlignment="viewStart" />
+            android:paddingTop="8dp"
+            android:textAlignment="viewStart"
+            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textColor="?android:attr/textColorPrimary" />
 
     </LinearLayout>
 
diff --git a/packages/DocumentsUI/res/layout/item_message_list.xml b/packages/DocumentsUI/res/layout/item_message_list.xml
index 2bcbc2d..44c8baf 100644
--- a/packages/DocumentsUI/res/layout/item_message_list.xml
+++ b/packages/DocumentsUI/res/layout/item_message_list.xml
@@ -17,23 +17,28 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/item_background"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:minHeight="@dimen/list_item_height"
+    android:paddingStart="@dimen/list_item_padding"
+    android:paddingEnd="@dimen/list_item_padding"
     android:paddingTop="8dp"
     android:paddingBottom="8dp"
+    android:gravity="center_vertical"
     android:orientation="horizontal"
     android:baselineAligned="false">
 
-    <ImageView
-        android:id="@android:id/icon"
-        android:layout_width="@android:dimen/app_icon_size"
-        android:layout_height="@android:dimen/app_icon_size"
-        android:layout_marginEnd="8dp"
-        android:layout_gravity="center_vertical"
-        android:scaleType="centerInside"
-        android:contentDescription="@null" />
+    <FrameLayout
+        android:layout_width="@dimen/icon_size"
+        android:layout_height="@dimen/icon_size"
+        android:layout_marginEnd="16dp">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
+
+    </FrameLayout>
 
     <TextView
         android:id="@android:id/title"
@@ -43,6 +48,7 @@
         android:maxLines="2"
         android:ellipsize="end"
         android:textAlignment="viewStart"
-        android:textAppearance="?android:attr/textAppearanceSmall" />
+        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+        android:textColor="?android:attr/textColorPrimary" />
 
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid.xml b/packages/DocumentsUI/res/values-ldrtl/dimens.xml
similarity index 74%
copy from packages/DocumentsUI/res/drawable/item_doc_grid.xml
copy to packages/DocumentsUI/res/values-ldrtl/dimens.xml
index 3f036f7..22f8131 100644
--- a/packages/DocumentsUI/res/drawable/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/values-ldrtl/dimens.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_grid_card_background" />
-</selector>
+<resources>
+    <bool name="list_divider_inset_left">false</bool>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
index 961608c..c9dee8d 100644
--- a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
@@ -16,4 +16,10 @@
 
 <resources>
     <bool name="always_show_summary">true</bool>
+
+    <dimen name="list_item_height">64dp</dimen>
+    <dimen name="list_item_padding">24dp</dimen>
+
+    <dimen name="list_divider_inset">80dp</dimen>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
index 3a75dfa..75afe01 100644
--- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -20,5 +20,9 @@
     <item type="dimen" name="dialog_width">85%</item>
     <item type="dimen" name="dialog_height">90%</item>
 
-    <dimen name="grid_padding_horiz">20dp</dimen>
+    <dimen name="grid_padding_horiz">24dp</dimen>
+    <dimen name="grid_padding_vert">8dp</dimen>
+
+    <dimen name="grid_item_padding">8dp</dimen>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index adeff77..e3d7f2d 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -18,4 +18,9 @@
     <color name="chip">#ddd</color>
     <color name="item_root_pressed">#33cccccc</color>
     <color name="item_root_focused">#66cccccc</color>
+
+    <color name="grid_item_background">#ffe1e1e0</color>
+
+    <color name="accent_item_activated">#88009587</color>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index 924a8d6..83a0bf4 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -15,14 +15,26 @@
 -->
 
 <resources>
-    <dimen name="icon_size">32dp</dimen>
+    <dimen name="icon_size">40dp</dimen>
     <dimen name="root_icon_size">24dp</dimen>
-    <dimen name="grid_width">160dp</dimen>
-    <dimen name="grid_height">170dp</dimen>
 
-    <dimen name="grid_padding">4dp</dimen>
+    <dimen name="grid_width">160dp</dimen>
+    <dimen name="grid_height">176dp</dimen>
+
+    <dimen name="grid_item_width">160dp</dimen>
+    <dimen name="grid_item_height">176dp</dimen>
+    <dimen name="grid_item_padding">4dp</dimen>
+
     <dimen name="grid_padding_horiz">4dp</dimen>
+    <dimen name="grid_padding_vert">4dp</dimen>
+
+    <dimen name="list_item_height">72dp</dimen>
+    <dimen name="list_item_padding">16dp</dimen>
+
+    <dimen name="list_divider_inset">72dp</dimen>
+    <bool name="list_divider_inset_left">true</bool>
 
     <bool name="show_as_dialog">false</bool>
     <bool name="always_show_summary">false</bool>
+
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
index 77595b6..00b3c87 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
@@ -29,12 +29,18 @@
 
     public DirectoryContainerView(Context context) {
         super(context);
-        setClipChildren(false);
     }
 
     public DirectoryContainerView(Context context, AttributeSet attrs) {
         super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
         setClipChildren(false);
+        setClipToOutline(false);
+        setClipToPadding(false);
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 9069a55..e013cc3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -38,6 +38,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.Loader;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Point;
@@ -187,6 +188,7 @@
     public View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         final Context context = inflater.getContext();
+        final Resources res = context.getResources();
         final View view = inflater.inflate(R.layout.fragment_directory, container, false);
 
         mEmptyView = view.findViewById(android.R.id.empty);
@@ -196,6 +198,16 @@
         mListView.setMultiChoiceModeListener(mMultiListener);
         mListView.setRecyclerListener(mRecycleListener);
 
+        // Indent our list divider to align with text
+        final Drawable divider = mListView.getDivider();
+        final boolean insetLeft = res.getBoolean(R.bool.list_divider_inset_left);
+        final int insetSize = res.getDimensionPixelSize(R.dimen.list_divider_inset);
+        if (insetLeft) {
+            mListView.setDivider(new InsetDrawable(divider, insetSize, 0, 0, 0));
+        } else {
+            mListView.setDivider(new InsetDrawable(divider, 0, 0, insetSize, 0));
+        }
+
         mGridView = (GridView) view.findViewById(R.id.grid);
         mGridView.setOnItemClickListener(mItemListener);
         mGridView.setMultiChoiceModeListener(mMultiListener);
@@ -693,11 +705,11 @@
             if (extras != null) {
                 final String info = extras.getString(DocumentsContract.EXTRA_INFO);
                 if (info != null) {
-                    mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info, info));
+                    mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info_dark, info));
                 }
                 final String error = extras.getString(DocumentsContract.EXTRA_ERROR);
                 if (error != null) {
-                    mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, error));
+                    mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert_dark, error));
                 }
                 if (extras.getBoolean(DocumentsContract.EXTRA_LOADING, false)) {
                     mFooters.add(new LoadingFooter());
@@ -706,7 +718,7 @@
 
             if (result != null && result.exception != null) {
                 mFooters.add(new MessageFooter(
-                        3, R.drawable.ic_dialog_alert, getString(R.string.query_error)));
+                        3, R.drawable.ic_dialog_alert_dark, getString(R.string.query_error)));
             }
 
             if (isEmpty()) {
@@ -748,21 +760,6 @@
                     convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
                 } else if (state.derivedMode == MODE_GRID) {
                     convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
-
-                    // Apply padding to grid items
-                    final FrameLayout grid = (FrameLayout) convertView;
-                    final int gridPadding = getResources()
-                            .getDimensionPixelSize(R.dimen.grid_padding);
-
-                    // Tricksy hobbitses! We need to fully clear the drawable so
-                    // the view doesn't clobber the new InsetDrawable callback
-                    // when setting back later.
-                    final Drawable fg = grid.getForeground();
-                    final Drawable bg = grid.getBackground();
-                    grid.setForeground(null);
-                    grid.setBackground(null);
-                    grid.setForeground(new InsetDrawable(fg, gridPadding));
-                    grid.setBackground(new InsetDrawable(bg, gridPadding));
                 } else {
                     throw new IllegalStateException();
                 }
@@ -882,7 +879,8 @@
                 // hint to remind user they're a directory.
                 if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
                         && showThumbnail) {
-                    iconDrawable = context.getResources().getDrawable(R.drawable.ic_root_folder);
+                    iconDrawable = context.getResources().getDrawable(
+                            R.drawable.ic_root_folder_dark);
                 }
 
                 if (summary != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
index b552e5a..c163c46 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -40,8 +40,13 @@
     public void setBackground(Drawable background) {
         final Rect rect = new Rect();
         background.getPadding(rect);
-        final InsetDrawable inset = new InsetDrawable(background, -rect.left, 0, -rect.right, 0);
-        super.setBackground(inset);
+
+        final boolean insetLeft = getResources().getBoolean(R.bool.list_divider_inset_left);
+        if (insetLeft) {
+            super.setBackground(new InsetDrawable(background, -rect.left, 0, -rect.right, 0));
+        } else {
+            super.setBackground(new InsetDrawable(background, -rect.right, 0, -rect.left, 0));
+        }
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index 71fd100..eaa74eb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -45,7 +45,7 @@
         add("application/vnd.android.package-archive", icon);
 
         // Audio
-        icon = R.drawable.ic_doc_audio;
+        icon = R.drawable.ic_doc_audio_dark;
         add("application/ogg", icon);
         add("application/x-flac", icon);
 
@@ -132,7 +132,7 @@
         add("application/x-font-ttf", icon);
 
         // Image
-        icon = R.drawable.ic_doc_image;
+        icon = R.drawable.ic_doc_image_dark;
         add("application/vnd.oasis.opendocument.graphics", icon);
         add("application/vnd.oasis.opendocument.graphics-template", icon);
         add("application/vnd.oasis.opendocument.image", icon);
@@ -186,7 +186,7 @@
         add("application/x-kword", icon);
 
         // Video
-        icon = R.drawable.ic_doc_video;
+        icon = R.drawable.ic_doc_video_dark;
         add("application/x-quicktimeplayer", icon);
         add("application/x-shockwave-flash", icon);
     }
@@ -220,7 +220,7 @@
             if (mode == DocumentsActivity.State.MODE_GRID) {
                 return res.getDrawable(R.drawable.ic_grid_folder);
             } else {
-                return res.getDrawable(R.drawable.ic_root_folder);
+                return res.getDrawable(R.drawable.ic_root_folder_dark);
             }
         }
 
@@ -232,7 +232,7 @@
 
         if (Document.MIME_TYPE_DIR.equals(mimeType)) {
             // TODO: return a mipmap, since this is used for grid
-            return res.getDrawable(R.drawable.ic_root_folder);
+            return res.getDrawable(R.drawable.ic_root_folder_dark);
         }
 
         // Look for exact match first
@@ -249,13 +249,13 @@
         // Otherwise look for partial match
         final String typeOnly = mimeType.split("/")[0];
         if ("audio".equals(typeOnly)) {
-            return res.getDrawable(R.drawable.ic_doc_audio);
+            return res.getDrawable(R.drawable.ic_doc_audio_dark);
         } else if ("image".equals(typeOnly)) {
-            return res.getDrawable(R.drawable.ic_doc_image);
+            return res.getDrawable(R.drawable.ic_doc_image_dark);
         } else if ("text".equals(typeOnly)) {
             return res.getDrawable(R.drawable.ic_doc_text);
         } else if ("video".equals(typeOnly)) {
-            return res.getDrawable(R.drawable.ic_doc_video);
+            return res.getDrawable(R.drawable.ic_doc_video_dark);
         } else {
             return res.getDrawable(R.drawable.ic_doc_generic);
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index caa7581..d06e858 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -103,7 +103,7 @@
         // Special root for recents
         mRecentsRoot.authority = null;
         mRecentsRoot.rootId = null;
-        mRecentsRoot.icon = R.drawable.ic_root_recent;
+        mRecentsRoot.icon = R.drawable.ic_root_recent_dark;
         mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE
                 | Root.FLAG_SUPPORTS_IS_CHILD;
         mRecentsRoot.title = mContext.getString(R.string.root_recent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index e220c9e..efa7785 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -159,15 +159,15 @@
 
         // TODO: remove these special case icons
         if (isExternalStorage()) {
-            derivedIcon = R.drawable.ic_root_sdcard;
+            derivedIcon = R.drawable.ic_root_sdcard_dark;
         } else if (isDownloads()) {
-            derivedIcon = R.drawable.ic_root_download;
+            derivedIcon = R.drawable.ic_root_download_dark;
         } else if (isImages()) {
-            derivedIcon = R.drawable.ic_doc_image;
+            derivedIcon = R.drawable.ic_doc_image_dark;
         } else if (isVideos()) {
-            derivedIcon = R.drawable.ic_doc_video;
+            derivedIcon = R.drawable.ic_doc_video_dark;
         } else if (isAudio()) {
-            derivedIcon = R.drawable.ic_doc_audio;
+            derivedIcon = R.drawable.ic_doc_audio_dark;
         }
     }
 
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-hdpi/ic_alarm_small.png
deleted file mode 100644
index 3819029..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-mdpi/ic_alarm_small.png
deleted file mode 100644
index 2aeedaf..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_alarm_small.png
deleted file mode 100644
index e28b3f6..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_alarm_small.png
deleted file mode 100644
index f727d01..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_alarm_small.png
deleted file mode 100644
index d9c0623..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-xxhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-sw600dp-xxhdpi/ic_alarm_small.png
deleted file mode 100644
index a36bf1f..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-xxhdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-xhdpi/ic_alarm_small.png
deleted file mode 100644
index 0290bdc..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/ic_alarm_small.png b/packages/Keyguard/res/drawable-xxhdpi/ic_alarm_small.png
deleted file mode 100644
index 66968e8..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/ic_alarm_small.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable/ic_access_alarms_big.xml b/packages/Keyguard/res/drawable/ic_access_alarms_big.xml
new file mode 100644
index 0000000..84ccb7c
--- /dev/null
+++ b/packages/Keyguard/res/drawable/ic_access_alarms_big.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="18dp"
+    android:height="18dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="@color/clock_gray"
+        android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/Keyguard/res/drawable/ic_backspace_24dp.xml b/packages/Keyguard/res/drawable/ic_backspace_24dp.xml
index 9e5016d..47c8d14 100644
--- a/packages/Keyguard/res/drawable/ic_backspace_24dp.xml
+++ b/packages/Keyguard/res/drawable/ic_backspace_24dp.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
-        android:height="24dp"/>
-
-    <viewport
+        android:height="24dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#ffffffff"
+        android:fillColor="#ffffffff"
         android:pathData="M44.0,6.0L14.0,6.0c-1.4,0.0 -2.5,0.7 -3.2,1.8L0.0,24.0l10.8,16.2c0.7,1.1 1.8,1.8 3.2,1.8l30.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L48.0,10.0C48.0,7.8 46.2,6.0 44.0,6.0zM38.0,31.2L35.2,34.0L28.0,26.8L20.8,34.0L18.0,31.2l7.2,-7.2L18.0,16.8l2.8,-2.8l7.2,7.2l7.2,-7.2l2.8,2.8L30.8,24.0L38.0,31.2z"/>
 </vector>
diff --git a/packages/Keyguard/res/layout/keyguard_status_area.xml b/packages/Keyguard/res/layout/keyguard_status_area.xml
index 2730517..7d8977c 100644
--- a/packages/Keyguard/res/layout/keyguard_status_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_area.xml
@@ -35,13 +35,11 @@
     <TextView android:id="@+id/alarm_status"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:drawablePadding="2dip"
-        android:drawableLeft="@drawable/ic_alarm_small"
-        android:drawableStart="@drawable/ic_alarm_small"
+        android:drawablePadding="6dp"
+        android:drawableStart="@drawable/ic_access_alarms_big"
         android:textColor="@color/clock_gray"
         style="@style/widget_label"
-        android:layout_marginLeft="8dip"
-        android:layout_marginStart="8dip"
+        android:layout_marginStart="6dp"
         android:gravity="center"
         android:visibility="gone"
         />
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 09f521a..1e124b8 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -22,9 +22,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入 SIM 卡 PUK 码和新的 PIN 码"</string>
-    <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM 卡 PUK 码"</string>
-    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"新 SIM 卡 PIN 码"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入SIM卡PUK码和新的 PIN 码"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM卡PUK码"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"新SIM卡PIN码"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"触摸可输入密码"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"输入密码以解锁"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"输入 PIN 进行解锁"</string>
@@ -36,16 +36,16 @@
     <string name="keyguard_low_battery" msgid="8143808018719173859">"请连接充电器。"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按“菜单”键解锁。"</string>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"网络已锁定"</string>
-    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无 SIM 卡"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板电脑中没有 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手机中没有 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"请插入 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM 卡缺失或无法读取,请插入 SIM 卡。"</string>
-    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM 卡无法使用。"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的 SIM 卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string>
-    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡已被锁定。"</string>
-    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡已被 PUK 锁定。"</string>
-    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解锁 SIM 卡..."</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无SIM卡"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板电脑中没有SIM卡。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手机中没有SIM卡。"</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"请插入SIM卡。"</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM卡缺失或无法读取,请插入SIM卡。"</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM卡无法使用。"</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的SIM卡已永久停用。\n请与您的无线服务提供商联系,以便重新获取一张SIM卡。"</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM卡已被锁定。"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM卡已被PUK码锁定。"</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解锁SIM卡..."</string>
     <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。%3$d的小部件%2$d。"</string>
     <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"添加小部件。"</string>
     <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
@@ -106,16 +106,16 @@
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string>
-    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入 SIM PIN"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入SIM卡PIN码"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"输入密码"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡已被停用,需要输入 PUK 码才能继续使用。有关详情,请联系您的运营商。"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM卡已被停用,需要输入PUK码才能继续使用。有关详情,请联系您的运营商。"</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"请输入所需 PIN 码"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"请确认所需 PIN 码"</string>
-    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁 SIM 卡..."</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁SIM卡..."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 码应至少包含 8 位数字。"</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的 PUK 码。如果尝试错误次数过多,SIM 卡将永久停用。"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK码应至少包含8位数字。"</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 码不匹配"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的 Google 帐户。"</string>
@@ -136,18 +136,18 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"删除"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM 卡 PIN 码不正确,您现在必须联系运营商为您解锁设备。"</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM卡PIN码不正确,您现在必须联系运营商为您解锁设备。"</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM 卡 PIN 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,则必须联系运营商帮您解锁设备。"</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM 卡 PIN 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。"</item>
+    <item quantity="one" msgid="8134313997799638254">"SIM卡PIN码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,则必须联系运营商帮您解锁设备。"</item>
+    <item quantity="other" msgid="2215723361575359486">"SIM卡PIN码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。"</item>
   </plurals>
-    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM 卡无法使用,请与您的运营商联系。"</string>
+    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM卡无法使用,请与您的运营商联系。"</string>
   <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM 卡 PUK 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将永远无法使用。"</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM 卡 PUK 码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM 卡将永远无法使用。"</item>
+    <item quantity="one" msgid="3256893607561060649">"SIM卡PUK码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将永远无法使用。"</item>
+    <item quantity="other" msgid="5477305226026342036">"SIM卡PUK码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将永远无法使用。"</item>
   </plurals>
-    <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM 卡 PIN 码操作失败!"</string>
-    <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM 卡 PUK 码操作失败!"</string>
+    <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM卡PIN码操作失败!"</string>
+    <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM卡PUK码操作失败!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"代码正确!"</string>
     <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"“上一曲”按钮"</string>
     <string name="keyguard_transport_next_description" msgid="4299258300283778305">"“下一曲”按钮"</string>
diff --git a/packages/Keyguard/res/values/donottranslate.xml b/packages/Keyguard/res/values/donottranslate.xml
index 78636db..2f54406 100644
--- a/packages/Keyguard/res/values/donottranslate.xml
+++ b/packages/Keyguard/res/values/donottranslate.xml
@@ -18,6 +18,9 @@
     <!-- Skeleton string format for displaying the date. -->
     <string name="abbrev_wday_month_day_no_year">EEEEMMMMd</string>
 
+    <!-- Skeleton string format for displaying the date when an alarm is set. -->
+    <string name="abbrev_wday_month_day_no_year_alarm">EEEMMMMd</string>
+
     <!-- Skeleton string format for displaying the time in 12-hour format. -->
     <string name="clock_12hr_format">hm</string>
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 02a441b..daba0a2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -71,6 +71,12 @@
         public void onScreenTurnedOff(int why) {
             setEnableMarquee(false);
         }
+
+        @Override
+        public void onUserSwitchComplete(int userId) {
+            refresh();
+            updateOwnerInfo();
+        }
     };
 
     public KeyguardStatusView(Context context) {
@@ -110,7 +116,8 @@
     }
 
     protected void refresh() {
-        Patterns.update(mContext);
+        AlarmClockInfo nextAlarm = mLockPatternUtils.getNextAlarm();
+        Patterns.update(mContext, nextAlarm != null);
 
         mDateView.setFormat24Hour(Patterns.dateView);
         mDateView.setFormat12Hour(Patterns.dateView);
@@ -118,25 +125,23 @@
         mClockView.setFormat12Hour(Patterns.clockView12);
         mClockView.setFormat24Hour(Patterns.clockView24);
 
-        refreshAlarmStatus();
+        refreshAlarmStatus(nextAlarm);
     }
 
-    void refreshAlarmStatus() {
-        // Update Alarm status
-        AlarmClockInfo nextAlarm = mLockPatternUtils.getNextAlarm();
+    void refreshAlarmStatus(AlarmClockInfo nextAlarm) {
         if (nextAlarm != null) {
-            mAlarmStatusView.setText(formatNextAlarm(nextAlarm));
+            mAlarmStatusView.setText(formatNextAlarm(mContext, nextAlarm));
             mAlarmStatusView.setVisibility(View.VISIBLE);
         } else {
             mAlarmStatusView.setVisibility(View.GONE);
         }
     }
 
-    String formatNextAlarm(AlarmClockInfo info) {
+    public static String formatNextAlarm(Context context, AlarmClockInfo info) {
         if (info == null) {
             return "";
         }
-        String skeleton = DateFormat.is24HourFormat(mContext) ? "EHm" : "Ehma";
+        String skeleton = DateFormat.is24HourFormat(context) ? "EHm" : "Ehma";
         String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
         return DateFormat.format(pattern, info.getTriggerTime()).toString();
     }
@@ -191,10 +196,12 @@
         static String clockView24;
         static String cacheKey;
 
-        static void update(Context context) {
+        static void update(Context context, boolean hasAlarm) {
             final Locale locale = Locale.getDefault();
             final Resources res = context.getResources();
-            final String dateViewSkel = res.getString(R.string.abbrev_wday_month_day_no_year);
+            final String dateViewSkel = res.getString(hasAlarm
+                    ? R.string.abbrev_wday_month_day_no_year_alarm
+                    : R.string.abbrev_wday_month_day_no_year);
             final String clockView12Skel = res.getString(R.string.clock_12hr_format);
             final String clockView24Skel = res.getString(R.string.clock_24hr_format);
             final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a5dbbcb..f0f5772 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -17,6 +17,7 @@
 package com.android.keyguard;
 
 import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
 import android.app.IUserSwitchObserver;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
@@ -322,7 +323,8 @@
 
             if (Intent.ACTION_TIME_TICK.equals(action)
                     || Intent.ACTION_TIME_CHANGED.equals(action)
-                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
+                    || AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) {
                 mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
             } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
                 mTelephonyPlmn = getTelephonyPlmnFrom(intent);
@@ -568,6 +570,7 @@
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
         context.registerReceiver(mBroadcastReceiver, filter);
 
         final IntentFilter bootCompleteFilter = new IntentFilter();
diff --git a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
index f3125f1..a7c9105 100644
--- a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
@@ -38,6 +38,10 @@
           android:label="@string/app_name"
           android:exported="true"
           android:launchMode="singleInstance" >
+          <intent-filter>
+              <action android:name="android.intent.action.MAIN" />
+              <category android:name="android.intent.category.LAUNCHER" />
+          </intent-filter>
       </activity>
     </application>
 </manifest>
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
index 01b107b..06a06bf 100644
--- a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
@@ -17,9 +17,9 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent">
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
     <Button android:id="@+id/enable_trust"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -28,6 +28,10 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="Revoke trust" />
+    <Button android:id="@+id/crash"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Crash" />
     <CheckBox android:id="@+id/report_unlock_attempts"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
index 8e293fb..6b5f78b 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
@@ -37,6 +37,7 @@
 
         findViewById(R.id.enable_trust).setOnClickListener(this);
         findViewById(R.id.revoke_trust).setOnClickListener(this);
+        findViewById(R.id.crash).setOnClickListener(this);
 
         mReportUnlockAttempts = (CheckBox) findViewById(R.id.report_unlock_attempts);
         mReportUnlockAttempts.setOnCheckedChangeListener(this);
@@ -56,6 +57,8 @@
                     null /* extra */);
         } else if (id == R.id.revoke_trust) {
             SampleTrustAgent.sendRevokeTrust(this);
+        } else if (id == R.id.crash) {
+            throw new RuntimeException("crash");
         }
     }
 
diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_menu_savetopdf.png b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_savetopdf.png
new file mode 100644
index 0000000..639a63f
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_savetopdf.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_menu_savetopdf.png b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_savetopdf.png
new file mode 100644
index 0000000..ce6d75b
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_savetopdf.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_savetopdf.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_savetopdf.png
new file mode 100644
index 0000000..98872f4
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_savetopdf.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xxhdpi/ic_menu_savetopdf.png b/packages/PrintSpooler/res/drawable-xxhdpi/ic_menu_savetopdf.png
new file mode 100644
index 0000000..4fba4e0
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xxhdpi/ic_menu_savetopdf.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xxxhdpi/ic_menu_savetopdf.png b/packages/PrintSpooler/res/drawable-xxxhdpi/ic_menu_savetopdf.png
new file mode 100644
index 0000000..42d8672
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xxxhdpi/ic_menu_savetopdf.png
Binary files differ
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index 3678cf2..c3ddad9 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -76,8 +76,13 @@
         public void onPageContentAvailable(BitmapDrawable content);
     }
 
-    public PageContentRepository(Context context) {
-        mRenderer = new AsyncRenderer(context);
+    public interface OnMalformedPdfFileListener {
+        public void onMalformedPdfFile();
+    }
+
+    public PageContentRepository(Context context,
+            OnMalformedPdfFileListener malformedPdfFileListener) {
+        mRenderer = new AsyncRenderer(context, malformedPdfFileListener);
         mState = STATE_CLOSED;
         if (DEBUG) {
             Log.i(LOG_TAG, "STATE_CLOSED");
@@ -440,19 +445,24 @@
     }
 
     private static class AsyncRenderer {
+        private static final int MALFORMED_PDF_FILE_ERROR = -2;
+
         private final Context mContext;
 
         private final PageContentLruCache mPageContentCache;
 
         private final ArrayMap<Integer, RenderPageTask> mPageToRenderTaskMap = new ArrayMap<>();
 
+        private final OnMalformedPdfFileListener mOnMalformedPdfFileListener;
+
         private int mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
 
         // Accessed only by the executor thread.
         private PdfRenderer mRenderer;
 
-        public AsyncRenderer(Context context) {
+        public AsyncRenderer(Context context, OnMalformedPdfFileListener malformedPdfFileListener) {
             mContext = context;
+            mOnMalformedPdfFileListener = malformedPdfFileListener;
 
             ActivityManager activityManager = (ActivityManager)
                     mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -474,13 +484,19 @@
                         mRenderer = new PdfRenderer(source);
                         return mRenderer.getPageCount();
                     } catch (IOException ioe) {
-                        throw new IllegalStateException("Cannot open PDF document");
+                        Log.e(LOG_TAG, "Cannot open PDF document");
+                        return MALFORMED_PDF_FILE_ERROR;
                     }
                 }
 
                 @Override
                 public void onPostExecute(Integer pageCount) {
-                    mPageCount = pageCount;
+                    if (pageCount == MALFORMED_PDF_FILE_ERROR) {
+                        mOnMalformedPdfFileListener.onMalformedPdfFile();
+                        mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
+                    } else {
+                        mPageCount = pageCount;
+                    }
                     if (callback != null) {
                         callback.run();
                     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 30808ba..e976936 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -32,7 +32,6 @@
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.widget.CheckBox;
 import android.widget.TextView;
 import com.android.printspooler.R;
 import com.android.printspooler.model.PageContentRepository;
@@ -48,7 +47,8 @@
 /**
  * This class represents the adapter for the pages in the print preview list.
  */
-public final class PageAdapter extends Adapter {
+public final class PageAdapter extends Adapter implements
+        PageContentRepository.OnMalformedPdfFileListener{
     private static final String LOG_TAG = "PageAdapter";
 
     private static final int MAX_PREVIEW_PAGES_BATCH = 50;
@@ -75,7 +75,7 @@
     private final Context mContext;
     private final LayoutInflater mLayoutInflater;
 
-    private final ContentUpdateRequestCallback mContentUpdateRequestCallback;
+    private final ContentCallbacks mCallbacks;
     private final PageContentRepository mPageContentRepository;
     private final PreviewArea mPreviewArea;
 
@@ -109,8 +109,9 @@
     private int mPageContentWidth;
     private int mPageContentHeight;
 
-    public interface ContentUpdateRequestCallback {
-        public void requestContentUpdate();
+    public interface ContentCallbacks {
+        public void onRequestContentUpdate();
+        public void onMalformedPdfFile();
     }
 
     public interface PreviewArea {
@@ -120,13 +121,12 @@
         public void setPadding(int left, int top, int right, int bottom);
     }
 
-    public PageAdapter(Context context, ContentUpdateRequestCallback updateRequestCallback,
-            PreviewArea previewArea) {
+    public PageAdapter(Context context, ContentCallbacks callbacks, PreviewArea previewArea) {
         mContext = context;
-        mContentUpdateRequestCallback = updateRequestCallback;
+        mCallbacks = callbacks;
         mLayoutInflater = (LayoutInflater) context.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        mPageContentRepository = new PageContentRepository(context);
+        mPageContentRepository = new PageContentRepository(context, this);
 
         mSelectedPageElevation = mContext.getResources().getDimension(
                 R.dimen.selected_page_elevation);
@@ -165,6 +165,11 @@
         }
     }
 
+    @Override
+    public void onMalformedPdfFile() {
+        mCallbacks.onMalformedPdfFile();
+    }
+
     public void onOrientationChanged() {
         mColumnCount = mContext.getResources().getInteger(
                 R.integer.preview_page_per_row_count);
@@ -199,7 +204,7 @@
                 // If we already requested all pages, just wait.
                 if (!Arrays.equals(ALL_PAGES_ARRAY, mRequestedPages)) {
                     mRequestedPages = ALL_PAGES_ARRAY;
-                    mContentUpdateRequestCallback.requestContentUpdate();
+                    mCallbacks.onRequestContentUpdate();
                 }
                 return;
             } else {
@@ -548,7 +553,7 @@
             if (DEBUG) {
                 Log.i(LOG_TAG, "Requesting pages: " + Arrays.toString(mRequestedPages));
             }
-            mContentUpdateRequestCallback.requestContentUpdate();
+            mCallbacks.onRequestContentUpdate();
         }
     }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index a01e45c..a1b1aec 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -92,11 +92,11 @@
 import java.util.regex.Pattern;
 
 public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
-        PrintErrorFragment.OnActionListener, PageAdapter.ContentUpdateRequestCallback,
+        PrintErrorFragment.OnActionListener, PageAdapter.ContentCallbacks,
         OptionsStateChangeListener, OptionsStateController {
     private static final String LOG_TAG = "PrintActivity";
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
 
@@ -121,6 +121,7 @@
     private static final int STATE_CREATE_FILE_FAILED = 4;
     private static final int STATE_PRINTER_UNAVAILABLE = 5;
     private static final int STATE_UPDATE_SLOW = 6;
+    private static final int STATE_PRINT_COMPLETED = 7;
 
     private static final int UI_STATE_PREVIEW = 0;
     private static final int UI_STATE_ERROR = 1;
@@ -304,6 +305,10 @@
                     spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_QUEUED, null);
                 } break;
 
+                case STATE_PRINT_COMPLETED: {
+                    spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_COMPLETED, null);
+                } break;
+
                 case STATE_CREATE_FILE_FAILED: {
                     spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_FAILED,
                             getString(R.string.print_write_error_message));
@@ -351,16 +356,26 @@
     }
 
     @Override
-    public void requestContentUpdate() {
+    public void onRequestContentUpdate() {
         if (canUpdateDocument()) {
             updateDocument(true, false);
         }
     }
 
     @Override
+    public void onMalformedPdfFile() {
+        mProgressMessageController.cancel();
+        ensureErrorUiShown(null, PrintErrorFragment.ACTION_RETRY);
+
+        setState(STATE_UPDATE_FAILED);
+
+        updateOptionsUi();
+    }
+
+    @Override
     public void onActionPerformed() {
-        if (mState == STATE_UPDATE_FAILED && canUpdateDocument()) {
-            updateDocument(true, true);
+        if (mState == STATE_UPDATE_FAILED
+                && canUpdateDocument() && updateDocument(true, true)) {
             ensurePreviewUiShown();
             setState(STATE_CONFIGURING);
             updateOptionsUi();
@@ -503,18 +518,15 @@
         switch (requestCode) {
             case ACTIVITY_REQUEST_CREATE_FILE: {
                 onStartCreateDocumentActivityResult(resultCode, data);
-            }
-            break;
+            } break;
 
             case ACTIVITY_REQUEST_SELECT_PRINTER: {
                 onSelectPrinterActivityResult(resultCode, data);
-            }
-            break;
+            } break;
 
             case ACTIVITY_REQUEST_POPULATE_ADVANCED_PRINT_OPTIONS: {
                 onAdvancedPrintOptionsActivityResult(resultCode, data);
-            }
-            break;
+            } break;
         }
     }
 
@@ -532,6 +544,8 @@
 
     private void onStartCreateDocumentActivityResult(int resultCode, Intent data) {
         if (resultCode == RESULT_OK && data != null) {
+            setState(STATE_PRINT_COMPLETED);
+            updateOptionsUi();
             Uri uri = data.getData();
             mPrintedDocument.writeContent(getContentResolver(), uri);
             // Calling finish here does not invoke lifecycle callbacks but we
@@ -699,7 +713,8 @@
 
     private static boolean isFinalState(int state) {
         return state == STATE_PRINT_CONFIRMED
-                || state == STATE_PRINT_CANCELED;
+                || state == STATE_PRINT_CANCELED
+                || state == STATE_PRINT_COMPLETED;
     }
 
     private void updateSelectedPagesFromPreview() {
@@ -1053,6 +1068,7 @@
         }
 
         if (mState == STATE_PRINT_CONFIRMED
+                || mState == STATE_PRINT_COMPLETED
                 || mState == STATE_PRINT_CANCELED
                 || mState == STATE_UPDATE_FAILED
                 || mState == STATE_CREATE_FILE_FAILED
@@ -1289,7 +1305,7 @@
         if (mDestinationSpinnerAdapter.getPdfPrinter() != mCurrentPrinter) {
             mPrintButton.setImageResource(com.android.internal.R.drawable.ic_print);
         } else {
-            mPrintButton.setImageResource(com.android.internal.R.drawable.ic_menu_save);
+            mPrintButton.setImageResource(R.drawable.ic_menu_savetopdf);
         }
         if ((mRangeOptionsSpinner.getSelectedItemPosition() == 1
                 && (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors()))
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 686f865..5ce3579 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -323,6 +323,19 @@
             </intent-filter>
         </activity>
 
+        <activity
+            android:name=".settings.BrightnessDialog"
+            android:label="@string/quick_settings_brightness_dialog_title"
+            android:theme="@android:style/Theme.DeviceDefault.Light.Dialog"
+            android:finishOnCloseSystemDialogs="true"
+            android:launchMode="singleInstance"
+            android:excludeFromRecents="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
 
         <!-- I dream of notifications -->
         <service
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png
deleted file mode 100644
index 2c55017..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png
deleted file mode 100644
index c6dc466..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png
deleted file mode 100644
index 8bca860..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png
deleted file mode 100644
index d42d9d6..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_access_alarms_small.xml b/packages/SystemUI/res/drawable/ic_access_alarms_small.xml
new file mode 100644
index 0000000..cf64689
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_access_alarms_small.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="#64ffffff"
+        android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
index 4a4c1c1..d8649e5 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle.xml
+++ b/packages/SystemUI/res/drawable/ic_account_circle.xml
@@ -13,14 +13,11 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
-        android:height="24dp"/>
-
-    <viewport
+        android:height="24dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <group
         android:scaleX="1.2"
@@ -28,7 +25,7 @@
         android:pivotX="12.0"
         android:pivotY="12.0">
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
     </group>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
index afcddf1..7b8b89f 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
+++ b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
@@ -16,14 +16,11 @@
   ~ limitations under the License
   -->
 
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
-        android:height="24dp"/>
-
-    <viewport
+        android:height="24dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <group
         android:scaleX="1.2"
@@ -31,7 +28,7 @@
         android:pivotX="12.0"
         android:pivotY="12.0">
     <path
-        android:fill="@color/qs_user_detail_icon_muted"
+        android:fillColor="@color/qs_user_detail_icon_muted"
         android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
     </group>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_chevron_left.xml b/packages/SystemUI/res/drawable/ic_chevron_left.xml
new file mode 100644
index 0000000..379382b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_chevron_left.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="36.0"
+        android:viewportHeight="36.0">
+
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M23.1,11.1l-2.1000004,-2.1000004 -9.0,9.0 9.0,9.0 2.1000004,-2.1000004 -6.8999996,-6.8999996z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_clear_all.xml b/packages/SystemUI/res/drawable/ic_clear_all.xml
new file mode 100644
index 0000000..187a420
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_clear_all.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32dp"
+        android:height="32dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M10.0,26.0l28.0,0.0l0.0,-4.0L10.0,22.0L10.0,26.0zM6.0,34.0l28.0,0.0l0.0,-4.0L6.0,30.0L6.0,34.0zM14.0,14.0l0.0,4.0l28.0,0.0l0.0,-4.0L14.0,14.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_24dp.xml b/packages/SystemUI/res/drawable/ic_lock_24dp.xml
index b2e486c..204af7e 100644
--- a/packages/SystemUI/res/drawable/ic_lock_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_lock_24dp.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24.0dp"
-        android:height="24.0dp"/>
-
-    <viewport
+        android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="@color/keyguard_affordance"
+        android:fillColor="@color/keyguard_affordance"
         android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml b/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml
index 28b16dd..c877f06 100644
--- a/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24.0dp"
-        android:height="24.0dp"/>
-
-    <viewport
+        android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="@color/keyguard_affordance"
+        android:fillColor="@color/keyguard_affordance"
         android:pathData="M12.0,17.0c1.1,0.0 2.0,-0.9 2.0,-2.0s-0.9,-2.0 -2.0,-2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0S10.9,17.0 12.0,17.0zM18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l1.9,0.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM18.0,20.0L6.0,20.0L6.0,10.0l12.0,0.0L18.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml b/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml
index e5737ee..2d77949 100644
--- a/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24.0dp"
-        android:height="24.0dp"/>
-
-    <viewport
+        android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="@color/recents_task_view_lock_to_app_button_color"
+        android:fillColor="@color/recents_task_view_lock_to_app_button_color"
         android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_power_low.xml b/packages/SystemUI/res/drawable/ic_power_low.xml
index 5bb7aba..ba99948 100644
--- a/packages/SystemUI/res/drawable/ic_power_low.xml
+++ b/packages/SystemUI/res/drawable/ic_power_low.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24.0dp"
-        android:height="24.0dp"/>
-
-    <viewport
+        android:height="24.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM26.0,37.0l-4.0,0.0l0.0,-4.0l4.0,0.0L26.0,37.0zM26.0,30.0l-4.0,0.0L22.0,15.0l4.0,0.0L26.0,30.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_power_saver.xml b/packages/SystemUI/res/drawable/ic_power_saver.xml
index 26e7375..2162d79 100644
--- a/packages/SystemUI/res/drawable/ic_power_saver.xml
+++ b/packages/SystemUI/res/drawable/ic_power_saver.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24.0dp"
-        android:height="24.0dp"/>
-
-    <viewport
+        android:height="24.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM32.0,28.0l-6.0,0.0l0.0,6.0l-4.0,0.0l0.0,-6.0l-6.0,0.0l0.0,-4.0l6.0,0.0l0.0,-6.0l4.0,0.0l0.0,6.0l6.0,0.0L32.0,28.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
index c68238f..79a9d409 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M26.0,18.0L26.0,7.0c0.0,-1.7 -1.3,-3.0 -3.0,-3.0c-1.7,0.0 -3.0,1.3 -3.0,3.0l0.0,7.4L35.7,30.0l6.3,2.0l0.0,-4.0L26.0,18.0zM6.0,10.5l10.0,10.0L4.0,28.0l0.0,4.0l16.0,-5.0l0.0,11.0l-4.0,3.0l0.0,3.0l7.0,-2.0l7.0,2.0l0.0,-3.0l-4.0,-3.0l0.0,-7.5L37.5,42.0l2.5,-2.5L8.5,8.0L6.0,10.5z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
index c1e3c7e..5d5d257 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
@@ -13,19 +13,16 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M20.4,18.0"/>
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M42.0,32.0l0.0,-4.0L26.0,18.0L26.0,7.0c0.0,-1.7 -1.3,-3.0 -3.0,-3.0c-1.7,0.0 -3.0,1.3 -3.0,3.0l0.0,11.0L4.0,28.0l0.0,4.0l16.0,-5.0l0.0,11.0l-4.0,3.0l0.0,3.0l7.0,-2.0l7.0,2.0l0.0,-3.0l-4.0,-3.0L26.0,27.0L42.0,32.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_back.xml b/packages/SystemUI/res/drawable/ic_qs_back.xml
index 52039f5..f00ba03 100644
--- a/packages/SystemUI/res/drawable/ic_qs_back.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_back.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M20.0,11.0L7.8,11.0l5.6,-5.6L12.0,4.0l-8.0,8.0l8.0,8.0l1.4,-1.4L7.8,13.0L20.0,13.0L20.0,11.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
index 3957d02..0c65389 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M14.0,24.0l-4.0,-4.0l-4.0,4.0l4.0,4.0L14.0,24.0zM35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6zM38.0,20.0l-4.0,4.0l4.0,4.0l4.0,-4.0L38.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml
index e4038f9..b9a315c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M28.5,24.0l4.6,4.6c0.6,-1.4 0.9,-3.0 0.9,-4.7c0.0,-1.6 -0.3,-3.2 -0.9,-4.6L28.5,24.0zM39.1,13.4L36.5,16.0c1.3,2.4 2.0,5.1 2.0,8.0s-0.7,5.6 -2.0,8.0l2.4,2.4c1.9,-3.1 3.1,-6.7 3.1,-10.6C42.0,20.0 40.9,16.5 39.1,13.4zM31.4,15.4L20.0,4.0l-2.0,0.0l0.0,15.2L8.8,10.0L6.0,12.8L17.2,24.0L6.0,35.2L8.8,38.0l9.2,-9.2L18.0,44.0l2.0,0.0l11.4,-11.4L22.8,24.0L31.4,15.4zM22.0,11.7l3.8,3.8L22.0,19.2L22.0,11.7zM25.8,32.6L22.0,36.3l0.0,-7.5L25.8,32.6z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml
index aa0b369..dd92126 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_detail_empty.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="56dp"
-        android:height="56dp"/>
-
-    <viewport
+        android:height="56dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="@color/qs_detail_empty"
+        android:fillColor="@color/qs_detail_empty"
         android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
index 00c5af8..0cb1f32 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M26.0,11.8l3.8,3.8l-3.2,3.2l2.8,2.8l6.0,-6.0L24.0,4.2l-2.0,0.0l0.0,10.1l4.0,4.0L26.0,11.8zM10.8,8.2L8.0,11.0l13.2,13.2L10.0,35.3l2.8,2.8L22.0,29.0l0.0,15.2l2.0,0.0l8.6,-8.6l4.6,4.6l2.8,-2.8L10.8,8.2zM26.0,36.5L26.0,29.0l3.8,3.8L26.0,36.5z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
index 2b14f33..9a68dad 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
index 2958848..0df1a96 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cancel.xml b/packages/SystemUI/res/drawable/ic_qs_cancel.xml
index de72f13..e4f4174 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cancel.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cancel.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
-        android:height="24dp"/>
-
-    <viewport
+        android:height="24dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M24.0,4.0C12.9,4.0 4.0,12.9 4.0,24.0s8.9,20.0 20.0,20.0c11.1,0.0 20.0,-8.9 20.0,-20.0S35.1,4.0 24.0,4.0zM34.0,31.2L31.2,34.0L24.0,26.8L16.8,34.0L14.0,31.2l7.2,-7.2L14.0,16.8l2.8,-2.8l7.2,7.2l7.2,-7.2l2.8,2.8L26.8,24.0L34.0,31.2z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml
index fbc21d4..59dcea2 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_detail_empty.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="56dp"
-        android:height="56dp"/>
-
-    <viewport
+        android:height="56dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="@color/qs_detail_empty"
+        android:fillColor="@color/qs_detail_empty"
         android:pathData="M42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
index 2a9541e..8051795 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
index 159bf65..794eb9e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM38.0,14.0L10.0,14.0l0.0,3.3c7.9,2.6 14.2,8.8 16.7,16.7L38.0,34.0L38.0,14.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0zM42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml b/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml
index 0f30be2..d4bd76f 100644
--- a/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml
@@ -13,22 +13,19 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64.0dp"
-        android:height="64.0dp"/>
-
-    <viewport
+        android:height="64.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M14.708,11.394l14.899,14.9l0.0,-6.771c4.359,-2.353 3.831,-7.489 3.831,-7.489l0.0,-0.64L14.708,11.393998z"/>
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M14.568,4.0l18.87,0.0l0.0,3.917l-18.87,0.0z"/>
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M38.284,39.427l-29.767,-29.766998 -2.4750004,2.4750004 12.351999,12.351 0.0,19.514 11.213001,0.0 0.0,-8.300999 6.2019978,6.2019997z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml b/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml
index 2e9d401..5514b44c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml
@@ -13,19 +13,16 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64.0dp"
-        android:height="64.0dp"/>
-
-    <viewport
+        android:height="64.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M33.438,12.034l0.0,-0.64l-18.87,0.0l0.0,0.64c0.0,0.0 -0.581,5.189 3.826,7.523L18.394,44.0l11.213,0.0L29.606998,19.523C33.966,17.17 33.438,12.034 33.438,12.034zM24.0,27.697c-1.523,0.0 -2.757,-1.234 -2.757,-2.757c0.0,-1.523 1.234,-2.757 2.757,-2.757c1.523,0.0 2.757,1.234 2.757,2.757C26.757,26.462 25.523,27.697 24.0,27.697z"/>
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M14.568,4.0l18.87,0.0l0.0,3.917l-18.87,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
index 0a00d14..d68ee4c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
@@ -13,16 +13,12 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64.0dp"
-        android:height="64.0dp"/>
-
-    <viewport
+        android:height="64.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
-
+        android:viewportHeight="48.0">
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M35.099998,28.500000c0.600000,-1.400000 0.900000,-2.900000 0.900000,-4.500000c0.000000,-6.600000 -5.400000,-12.000000 -12.000000,-12.000000c-1.600000,0.000000 -3.100000,0.300000 -4.500000,0.900000l3.200000,3.200000c0.400000,-0.100000 0.800000,-0.100000 1.200000,-0.100000c4.400000,0.000000 8.000000,3.600000 8.000000,8.000000c0.000000,0.400000 0.000000,0.800000 -0.100000,1.300000L35.099998,28.500000zM24.000000,8.000000c8.800000,0.000000 16.000000,7.200000 16.000000,16.000000c0.000000,2.700000 -0.700000,5.200000 -1.900000,7.500000l2.900000,2.900000c1.900000,-3.000000 3.000000,-6.600000 3.000000,-10.400000c0.000000,-11.000000 -9.000000,-20.000000 -20.000000,-20.000000c-3.800000,0.000000 -7.400000,1.100000 -10.400000,2.900000l2.900000,2.900000C18.700001,8.700000 21.299999,8.000000 24.000000,8.000000zM6.500000,5.000000L4.000000,7.500000l4.200000,4.200000C5.600000,15.100000 4.000000,19.400000 4.000000,24.000000c0.000000,7.400000 4.000000,13.800000 10.000000,17.299999l2.000000,-3.500000c-4.800000,-2.800000 -8.000000,-7.900000 -8.000000,-13.800000c0.000000,-3.500000 1.100000,-6.800000 3.100000,-9.400000l2.900000,2.900000C12.700000,19.400000 12.000000,21.600000 12.000000,24.000000c0.000000,4.400000 2.400000,8.300000 6.000000,10.400000l2.000000,-3.500000c-2.400000,-1.400000 -4.000000,-3.900000 -4.000000,-6.900000c0.000000,-1.300000 0.300000,-2.500000 0.900000,-3.600000l3.200000,3.200000c0.000000,0.100000 0.000000,0.300000 0.000000,0.400000c0.000000,2.200000 1.800000,4.000000 4.000000,4.000000c0.100000,0.000000 0.300000,0.000000 0.400000,0.000000l0.000000,0.000000l0.000000,0.000000l15.000000,15.000000l2.500000,-2.500000L8.500000,7.000000L6.500000,5.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
index 01cb0ab..da09f6e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64.0dp"
-        android:height="64.0dp"/>
-
-    <viewport
+        android:height="64.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M24.000000,22.000000c-2.200000,0.000000 -4.000000,1.800000 -4.000000,4.000000c0.000000,2.200000 1.800000,4.000000 4.000000,4.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000C28.000000,23.799999 26.200001,22.000000 24.000000,22.000000zM36.000000,26.000000c0.000000,-6.600000 -5.400000,-12.000000 -12.000000,-12.000000c-6.600000,0.000000 -12.000000,5.400000 -12.000000,12.000000c0.000000,4.400000 2.400000,8.300000 6.000000,10.400000l2.000000,-3.500000c-2.400000,-1.400000 -4.000000,-3.900000 -4.000000,-6.900000c0.000000,-4.400000 3.600000,-8.000000 8.000000,-8.000000s8.000000,3.600000 8.000000,8.000000c0.000000,3.000000 -1.600000,5.500000 -4.000000,6.900000l2.000000,3.500000C33.599998,34.299999 36.000000,30.400000 36.000000,26.000000zM24.000000,6.000000C13.000000,6.000000 4.000000,15.000000 4.000000,26.000000c0.000000,7.400000 4.000000,13.800000 10.000000,17.299999l2.000000,-3.500000c-4.800000,-2.800000 -8.000000,-7.900000 -8.000000,-13.800000c0.000000,-8.800000 7.200000,-16.000000 16.000000,-16.000000s16.000000,7.200000 16.000000,16.000000c0.000000,5.900000 -3.200000,11.100000 -8.000000,13.800000l2.000000,3.500000c6.000000,-3.500000 10.000000,-9.900000 10.000000,-17.299999C44.000000,15.000000 35.000000,6.000000 24.000000,6.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
index b6a5cad..4237b63 100644
--- a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M41.3,41.7L36.6,37.0L24.0,24.5l-7.1,-7.1L14.0,14.5L8.5,9.0L6.0,11.5l5.6,5.6c-5.1,6.3 -4.7,15.5 1.1,21.4c3.1,3.1 7.2,4.7 11.3,4.7c3.6,0.0 7.1,-1.2 10.1,-3.6l5.4,5.4l2.5,-2.5L41.3,41.7zM24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5c0.0,-2.6 0.9,-5.1 2.4,-7.2l9.6,9.6L24.0,39.2zM24.0,10.2l0.0,9.2l14.5,14.5c2.7,-5.9 1.7,-13.1 -3.2,-18.0L24.0,4.5l0.0,0.0l0.0,0.0L16.6,12.0l2.8,2.8L24.0,10.2z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
index e8d59e0..860e769 100644
--- a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M35.3,15.9L24.0,4.5l0.0,0.0l0.0,0.0L12.7,15.9c-6.2,6.2 -6.2,16.4 0.0,22.6c3.1,3.1 7.2,4.7 11.3,4.7s8.2,-1.6 11.3,-4.7C41.6,32.2 41.6,22.1 35.3,15.9zM24.0,39.2L24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5s1.2,-6.2 3.5,-8.5l8.5,-8.5L24.0,39.2z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_off.xml b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
index 26ebfbf..e0fe12e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
@@ -13,19 +13,16 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M24.0,13.0c2.8,0.0 5.0,2.2 5.0,5.0c0.0,1.5 -0.7,2.8 -1.7,3.7l7.3,7.3c2.0,-3.7 3.4,-7.6 3.4,-11.0c0.0,-7.7 -6.3,-14.0 -14.0,-14.0c-4.0,0.0 -7.5,1.6 -10.1,4.3l6.4,6.4C21.2,13.6 22.5,13.0 24.0,13.0zM32.7,32.2l-9.3,-9.3l-0.2,-0.2L6.5,6.0L4.0,8.5l6.4,6.4c-0.2,1.0 -0.4,2.0 -0.4,3.1c0.0,10.5 14.0,26.0 14.0,26.0s3.3,-3.7 6.8,-8.7l6.7,6.7l2.5,-2.5L32.7,32.2z"/>
     <path
         android:pathData="M23.5,22.9l0.0,0.0 -0.20000076,-0.19999886z"
-        android:fill="#4DFFFFFF"/>
+        android:fillColor="#4DFFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_on.xml b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
index bc73005..6a7cd53 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M24.0,4.0c-7.7,0.0 -14.0,6.3 -14.0,14.0c0.0,10.5 14.0,26.0 14.0,26.0s14.0,-15.5 14.0,-26.0C38.0,10.3 31.7,4.0 24.0,4.0zM24.0,23.0c-2.8,0.0 -5.0,-2.2 -5.0,-5.0s2.2,-5.0 5.0,-5.0c2.8,0.0 5.0,2.2 5.0,5.0S26.8,23.0 24.0,23.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
index 7b76e0f..4722c9e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_minus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
-        android:height="24dp"/>
-
-    <viewport
+        android:height="24dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0L14.0,26.0l0.0,-4.0l20.0,0.0L34.0,26.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
index 4b9f506..17d74cf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
-        android:height="24dp"/>
-
-    <viewport
+        android:height="24dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0l-8.0,0.0l0.0,8.0l-4.0,0.0l0.0,-8.0l-8.0,0.0l0.0,-4.0l8.0,0.0l0.0,-8.0l4.0,0.0l0.0,8.0l8.0,0.0L34.0,26.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
index 787eec5..9c5983d 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
index dd6be76..904ccdf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
index 96d20e8..a23c6f0 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml
index e4c7cb5..4bb3668 100644
--- a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M2.0,14.0l0.0,20.0c0.0,2.2 1.8,4.0 4.0,4.0l36.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,14.0c0.0,-2.2 -1.8,-4.0 -4.0,-4.0L6.0,10.0C3.8,10.0 2.0,11.8 2.0,14.0zM38.0,14.0l0.0,20.0L10.0,34.0L10.0,14.0L38.0,14.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml
index e4bf367..f0878c7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M34.0,2.0L14.0,2.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,36.0c0.0,2.2 1.8,4.0 4.0,4.0l20.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L38.0,6.0C38.0,3.8 36.2,2.0 34.0,2.0zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0L34.0,38.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
index a6c2cf8..6872a33 100644
--- a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
@@ -13,22 +13,19 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
+        android:height="64dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M10.25,1.75c-0.6,-0.6 -1.5,-0.6 -2.1,0.0l-6.4,6.4c-0.6,0.6 -0.6,1.5 0.0,2.1l12.0,12.0c0.6,0.6 1.5,0.6 2.1,0.0l6.4,-6.4c0.6,-0.6 0.6,-1.5 0.0,-2.1L10.25,1.75zM14.85,21.25l-12.0,-12.0l6.4,-6.4l12.0,12.0L14.85,21.25z"/>
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M16.55,2.5c3.3,1.5 5.6,4.7 6.0,8.5l1.5,0.0c-0.6,-6.2 -5.7,-11.0 -12.0,-11.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.55,2.5z"/>
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M7.55,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5l-1.4,0.0c0.5,6.2 5.6,11.0 11.9,11.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.55,21.5z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml
index 16fa30b..ad6b247 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_detail_empty.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="56dp"
-        android:height="56dp"/>
-
-    <viewport
+        android:height="56dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
         android:pathData="M24.0,4.0C15.0,4.0 6.7,7.0 0.0,12.0l24.0,32.0l24.0,-32.0C41.3,7.0 33.0,4.0 24.0,4.0z"
-        android:fill="@color/qs_detail_empty" />
+        android:fillColor="@color/qs_detail_empty" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_ringer_audible.xml
index 2969948..f358fa2 100644
--- a/packages/SystemUI/res/drawable/ic_ringer_audible.xml
+++ b/packages/SystemUI/res/drawable/ic_ringer_audible.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="32dp"
-        android:height="32dp"/>
-
-    <viewport
+        android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
index d8ded58..9642be3 100644
--- a/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="32dp"
-        android:height="32dp"/>
-
-    <viewport
+        android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
index a2f7822..9c78742 100644
--- a/packages/SystemUI/res/drawable/ic_settings_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
@@ -12,18 +12,15 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
 android:width="24dp"
-android:height="24dp"/>
-
-    <viewport android:viewportWidth="24.0"
-          android:viewportHeight="24.0"/>
+android:height="24dp" android:viewportWidth="24.0"
+          android:viewportHeight="24.0">
 
 
 <path
      android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
-     android:fill="#ffffffff"
+     android:fillColor="#ffffffff"
      />
 
 </vector>
diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml
new file mode 100644
index 0000000..07932d1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/notification_guts_bg_color" />
+    <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml b/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml
index 9137e7f..71400db 100644
--- a/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml
+++ b/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24.0dp"
-        android:height="24.0dp"/>
-
-    <viewport
+        android:height="24.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="@color/qs_tile_text"
+        android:fillColor="@color/qs_tile_text"
         android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/qs_subhead_caret.xml b/packages/SystemUI/res/drawable/qs_subhead_caret.xml
index f140bd0..13a168d 100644
--- a/packages/SystemUI/res/drawable/qs_subhead_caret.xml
+++ b/packages/SystemUI/res/drawable/qs_subhead_caret.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24.0dp"
-        android:height="24.0dp"/>
-
-    <viewport
+        android:height="24.0dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="@color/qs_subhead"
+        android:fillColor="@color/qs_subhead"
         android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
index 9c1165d..337c028 100644
--- a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
@@ -13,20 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="16dp"
-        android:width="16dp" />
-
-    <viewport
+        android:width="16dp"
         android:viewportHeight="100"
-        android:viewportWidth="100" />
+        android:viewportWidth="100" >
 
     <path
         android:name="x"
         android:pathData="M0,0L100,100M0,100L100,0z"
-        android:stroke="@color/recents_task_bar_dark_dismiss_color"
+        android:strokeColor="@color/recents_task_bar_dark_dismiss_color"
         android:strokeWidth="8.0"
         android:strokeLineCap="square" />
 
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
index a8afeb3..963ccf7 100644
--- a/packages/SystemUI/res/drawable/recents_dismiss_light.xml
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
@@ -13,21 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="16dp"
-        android:width="16dp" />
-
-    <viewport
+        android:width="16dp"
         android:viewportHeight="100"
-        android:viewportWidth="100" />
+        android:viewportWidth="100" >
 
 
     <path
         android:name="x"
         android:pathData="M0,0L100,100M0,100L100,0z"
-        android:stroke="@color/recents_task_bar_light_dismiss_color"
+        android:strokeColor="@color/recents_task_bar_light_dismiss_color"
         android:strokeWidth="8.0"
         android:strokeLineCap="square" />
 
diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm.xml b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
new file mode 100644
index 0000000..3b2bc31
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="18dp"
+    android:height="18dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
index e28490b..f53f0e4 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18dp"
-        android:height="18dp"/>
-
-    <viewport
+        android:height="18dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
index c012d14..2aac4ee 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18dp"
-        android:height="18dp"/>
-
-    <viewport
+        android:height="18dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M14.0,24.0l-4.0,-4.0l-4.0,4.0l4.0,4.0L14.0,24.0zM35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6zM38.0,20.0l-4.0,4.0l4.0,4.0l4.0,-4.0L38.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_no_sim.xml b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
index 70948b7..22d1d4b 100644
--- a/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18dp"
-        android:height="18dp"/>
-
-    <viewport
+        android:height="18dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#4DFFFFFF"
+        android:fillColor="#4DFFFFFF"
         android:pathData="M19.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-7.0,0.0L7.7,5.3L19.0,16.7L19.0,5.0zM3.7,3.9L2.4,5.2L5.0,7.8L5.0,19.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c0.4,0.0 0.7,-0.1 1.0,-0.3l1.9,1.9l1.3,-1.3L3.7,3.9z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index e1d63c3..352d86f 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="20dp"
-        android:height="20dp"/>
-
-    <viewport
+        android:height="20dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml
index 54a9b1b..73d7cba 100644
--- a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="20dp"
-        android:height="20dp"/>
-
-    <viewport
+        android:height="20dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportHeight="24.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml
index 101e3c4..d8ab078 100644
--- a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml
@@ -13,16 +13,13 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="19dp"
-        android:height="19dp"/>
-
-    <viewport
+        android:height="19dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"/>
+        android:viewportHeight="48.0">
 
     <path
-        android:fill="#FFFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0C44.0,13.0 35.0,4.0 24.0,4.0zM24.0,40.0c-8.8,0.0 -16.0,-7.2 -16.0,-16.0c0.0,-3.7 1.3,-7.1 3.4,-9.8l22.4,22.4C31.1,38.7 27.7,40.0 24.0,40.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8z"/>
 </vector>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index db5983b..f831570 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -22,25 +22,6 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     >
-    <com.android.systemui.statusbar.AlphaImageView
-        android:id="@+id/camera_button"
-        android:layout_height="64dp"
-        android:layout_width="64dp"
-        android:layout_gravity="bottom|end"
-        android:tint="#ffffffff"
-        android:src="@drawable/ic_camera_alt_24dp"
-        android:scaleType="center"
-        android:contentDescription="@string/accessibility_camera_button" />
-
-    <com.android.systemui.statusbar.AlphaImageView
-        android:id="@+id/phone_button"
-        android:layout_height="64dp"
-        android:layout_width="64dp"
-        android:layout_gravity="bottom|start"
-        android:tint="#ffffffff"
-        android:src="@drawable/ic_phone_24dp"
-        android:scaleType="center"
-        android:contentDescription="@string/accessibility_phone_button" />
 
     <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
         android:id="@+id/keyguard_indication_text"
@@ -52,7 +33,33 @@
         android:textColor="#ffffff"
         android:textAppearance="?android:attr/textAppearanceSmall"/>
 
-    <com.android.systemui.statusbar.AlphaImageView
+    <FrameLayout
+        android:id="@+id/preview_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    </FrameLayout>
+
+    <com.android.systemui.statusbar.KeyguardAffordanceView
+        android:id="@+id/camera_button"
+        android:layout_height="64dp"
+        android:layout_width="64dp"
+        android:layout_gravity="bottom|end"
+        android:tint="#ffffffff"
+        android:src="@drawable/ic_camera_alt_24dp"
+        android:scaleType="center"
+        android:contentDescription="@string/accessibility_camera_button" />
+
+    <com.android.systemui.statusbar.KeyguardAffordanceView
+        android:id="@+id/phone_button"
+        android:layout_height="64dp"
+        android:layout_width="64dp"
+        android:layout_gravity="bottom|start"
+        android:tint="#ffffffff"
+        android:src="@drawable/ic_phone_24dp"
+        android:scaleType="center"
+        android:contentDescription="@string/accessibility_phone_button" />
+
+    <com.android.systemui.statusbar.KeyguardAffordanceView
         android:id="@+id/lock_icon"
         android:layout_width="64dp"
         android:layout_height="64dp"
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
new file mode 100644
index 0000000..0e78d66
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/notification_guts_bg"
+    android:id="@+id/notification_guts"
+    android:visibility="gone"
+    android:clickable="true"
+    android:gravity="top|start"
+    >
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@android:dimen/notification_large_icon_height"
+            android:orientation="horizontal"
+            >
+
+        <ImageView android:id="@android:id/icon"
+               android:layout_width="@android:dimen/notification_large_icon_width"
+               android:layout_height="@android:dimen/notification_large_icon_height"
+               android:layout_weight="0"
+               android:padding="8dp"
+               android:scaleType="centerInside"
+               />
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start|center_vertical"
+            android:orientation="vertical"
+            android:paddingStart="8dp"
+            android:paddingEnd="8dp"
+            android:layout_weight="1"
+            >
+            <TextView
+                    android:id="@+id/pkgname"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_vertical|start"
+                    android:layout_weight="1"
+                    android:textAppearance="@*android:style/TextAppearance.StatusBar.Material.EventContent.Title"
+                    android:textColor="@color/notification_guts_title_color"
+                    />
+            <DateTimeView
+                    android:id="@+id/timestamp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0"
+                    android:layout_gravity="center_vertical|start"
+                    android:textAppearance="@*android:style/TextAppearance.StatusBar.Material.EventContent.Time"
+                    android:textColor="@color/notification_guts_text_color"
+                    />
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/debug_info"
+                    android:layout_weight="0"
+                    android:textAppearance="@*android:style/TextAppearance.StatusBar.Material.EventContent.Time"
+                    android:layout_gravity="bottom|start"
+                    android:visibility="gone"
+                    android:textColor="@color/notification_guts_text_color"
+                    />
+        </LinearLayout>
+
+        <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:padding="8dp"
+                android:layout_weight="0"
+                android:orientation="horizontal"
+                android:showDividers="beginning|middle"
+                android:divider="@*android:drawable/list_divider_holo_dark"
+                android:dividerPadding="8dp"
+                >
+            <Button style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+                    android:id="@+id/notification_inspect_item"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:gravity="start|center_vertical"
+                    android:drawablePadding="8dp"
+                    android:paddingStart="8dp"
+                    android:textColor="@color/notification_guts_btn_color"
+                    android:textSize="14dp"
+                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:text="@string/status_bar_notification_inspect_item_title"
+                    />
+        </LinearLayout>
+    </LinearLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 85668de..93c5538 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -67,8 +67,7 @@
         android:layout_width="match_parent"
         android:layout_height="@dimen/recents_task_view_lock_to_app_button_height"
         android:layout_gravity="center_horizontal|bottom"
-        android:background="@drawable/recents_lock_to_task_button_bg"
-        android:visibility="invisible">
+        android:background="@drawable/recents_lock_to_task_button_bg">
         <TextView
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 595d731..19dc36d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -87,7 +87,8 @@
                 android:layout_height="match_parent"
                 android:gravity="center_vertical"
                 >
-                <LinearLayout android:id="@+id/statusIcons"
+                <com.android.systemui.statusbar.AlphaOptimizedLinearLayout
+                    android:id="@+id/statusIcons"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:gravity="center_vertical"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1f68cd8..9af2879 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -56,14 +56,6 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <ViewStub
-                android:id="@+id/keyguard_user_switcher"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
-                android:layout_gravity="end"
-                android:layout="@layout/keyguard_user_switcher" />
-
         <com.android.systemui.statusbar.phone.ObservableScrollView
             android:id="@+id/scroll_view"
             android:layout_width="match_parent"
@@ -103,6 +95,14 @@
             android:layout_height="match_parent"
             android:layout_marginBottom="@dimen/close_handle_underlap"/>
 
+        <ViewStub
+            android:id="@+id/keyguard_user_switcher"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
+            android:layout_gravity="end"
+            android:layout="@layout/keyguard_user_switcher" />
+
     </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
 
     <include layout="@layout/status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 272904a..b260a4a 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -68,7 +68,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
-            android:layout_marginStart="8dp"
+            android:layout_marginStart="@dimen/header_battery_margin_keyguard"
             android:paddingEnd="@dimen/battery_level_padding_end"
             android:textColor="#ffffff"
             android:textSize="12sp"/>
@@ -87,24 +87,16 @@
         android:text="@*android:string/emergency_calls_only"
         android:gravity="center_vertical" />
 
-    <RelativeLayout
-        android:id="@+id/datetime"
+    <FrameLayout
+        android:id="@+id/date_group"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="start"
-        android:paddingTop="4dp"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
-        android:background="?android:attr/selectableItemBackground"
-        android:enabled="false"
-        >
-        <include layout="@layout/split_clock_view"
-            android:id="@+id/clock"
-            />
-
+        android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"
+        android:layout_alignParentBottom="true">
         <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
             android:layout_below="@id/clock"
@@ -113,17 +105,45 @@
         <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_expanded"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
             android:layout_below="@id/clock"
             systemui:datePattern="eeeeMMMMd"
             />
-    </RelativeLayout>
+    </FrameLayout>
+
+    <include layout="@layout/split_clock_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_above="@id/date_group"
+        android:id="@+id/clock"
+        />
+
+    <Button android:id="@+id/alarm_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_toEndOf="@id/date_group"
+        android:layout_marginBottom="4dp"
+        android:drawablePadding="6dp"
+        android:drawableStart="@drawable/ic_access_alarms_small"
+        android:textColor="#64ffffff"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
+        android:paddingEnd="6dp"
+        android:paddingStart="6dp"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp"
+        android:background="?android:attr/selectableItemBackground"
+        android:visibility="gone"
+        />
+
     <com.android.keyguard.CarrierText
         android:id="@+id/keyguard_carrier_text"
         android:layout_width="match_parent"
         android:layout_height="@dimen/status_bar_header_height_keyguard"
-        android:layout_marginLeft="16dp"
+        android:layout_marginStart="@dimen/keyguard_carrier_text_margin"
         android:layout_toStartOf="@id/system_icons_super_container"
         android:gravity="center_vertical"
         android:ellipsize="marquee"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
new file mode 100644
index 0000000..515270a
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
@@ -0,0 +1,40 @@
+<!--
+  ~ 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
+  -->
+
+<!-- Extends Framelayout -->
+<com.android.systemui.statusbar.DismissView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        >
+    <Button
+            android:id="@+id/dismiss_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minHeight="0dp"
+            android:textColor="#ffffffff"
+            android:text="@string/clear_all_notifications_text"
+            android:textSize="18sp"
+            android:textAllCaps="true"
+            android:paddingTop="@dimen/clear_all_padding_top"
+            android:paddingEnd="8dp"
+            android:layout_gravity="end|center_vertical"
+            android:drawableEnd="@drawable/ic_clear_all"
+            android:drawablePadding="4dp"
+            android:fontFamily="sans-serif-light"
+            android:background="@drawable/ripple_drawable" />
+</com.android.systemui.statusbar.DismissView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 7663d54..ef4e27c 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,3 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 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.
+-->
+
 <com.android.systemui.statusbar.ExpandableNotificationRow
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
@@ -35,17 +52,11 @@
         android:paddingStart="8dp"
         />
 
-    <TextView
-        android:id="@+id/debug_info"
-        android:visibility="invisible"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|end"
-        android:fontFamily="sans-serif-condensed"
-        android:textSize="9dp"
-        android:textStyle="bold"
-        android:textColor="#00A040"
-        android:padding="2dp"
+    <include
+        layout="@layout/notification_guts"
+        android:id="@+id/notification_guts"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         />
 
     <com.android.systemui.statusbar.NotificationScrimView
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index e3ac1c1..ac998f6 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -26,7 +26,7 @@
     android:fitsSystemWindows="true"
     android:descendantFocusability="afterDescendants">
 
-    <FrameLayout
+    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
             android:id="@+id/backdrop"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
@@ -41,7 +41,7 @@
                    android:layout_height="match_parent"
                    android:scaleType="centerCrop"
                    android:visibility="invisible" />
-    </FrameLayout>
+    </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
     <View android:id="@+id/scrim_behind"
         android:layout_width="match_parent"
@@ -54,7 +54,8 @@
     <com.android.systemui.statusbar.phone.PanelHolder
         android:id="@+id/panel_holder"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" >
+        android:layout_height="match_parent"
+        android:background="@color/transparent" >
         <include layout="@layout/status_bar_expanded"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/menu/notification_popup_menu.xml b/packages/SystemUI/res/menu/notification_popup_menu.xml
deleted file mode 100644
index 8923fb6..0000000
--- a/packages/SystemUI/res/menu/notification_popup_menu.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/notification_inspect_item" android:title="@string/status_bar_notification_inspect_item_title" />
-</menu>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 00715b2..785894a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skermkiekie geneem."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak om jou skermkiekie te sien."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kon nie skermkiekie neem nie."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Kon nie skermkiekie stoor nie. Geheue kan dalk in gebruik wees."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-lêeroordrag-opsies"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Heg as \'n mediaspeler (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Heg as \'n kamera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gas"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ gas"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Laat gas uitgaan"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Een minuut lank"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minute lank"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Maak batteryspaarder se instellings oop"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Laat gas uitgaan"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sal alles begin vasvang wat op jou skerm gewys word."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Moenie weer wys nie"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Begin nou"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d6e482b..4c9437f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"ቅጽበታዊ ገጽ እይታ ተቀርጿል"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"የአንተን ቅጽበታዊ ገጽ እይታ ለማየት ንካ"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ቅጽበታዊ ገጽ እይታ መቅረጽ አልተቻለም::"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"የማያ ፎቶማስቀመጥ አልተቻለም። ማከማቻም አገልግሎት ላይ ሊሆን ይችላል።"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"የUSB ፋይል ሰደዳ አማራጮች"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"እንደ ማህደረ አጫዋች (MTP) ሰካ"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"እንደ ካሜራ (PTP) ሰካ"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"እንግዳ"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ እንግዳ"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"እንግዳ ያስወጡ"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ለአንድ ደቂቃ"</item>
     <item quantity="other" msgid="6924190729213550991">"ለ%d ደቂቃዎች"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"የባትሪ ኃይል ቆጣቢ ቅንብሮች"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"እንግዳ ያስወጡ"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በማያ ገጽዎ ላይ የታየውን ነገር በሙሉ ማንሳት ይጀምራል።"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ዳግመኛ አታሳይ"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"አሁን ጀምር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 91a1a06..ae9e305 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"تم التقاط لقطة الشاشة."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"المس لعرض لقطة الشاشة."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"تعذر التقاط لقطة الشاشة."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"تعذر حفظ لقطة الشاشة. قد يكون التخزين قيد الاستخدام."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"‏خيارات نقل الملفات عبر USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏تحميل كمشغل وسائط (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏تحميل ككاميرا (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"المدعو"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ مدعو"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"الخروج من وضع الضيف"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"لمدة دقيقة واحدة"</item>
     <item quantity="other" msgid="6924190729213550991">"‏لمدة %d من الدقائق"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"فتح إعدادات وضع توفير الطاقة"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"الخروج من وضع الضيف"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> سيبدأ التقاط كل شيء يتم عرضه على الشاشة."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"عدم الإظهار مرة أخرى"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"البدء الآن"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 32ace8e..a166296 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Екранната снимка е заснета."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Докоснете, за да видите екранната си снимка."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Екранната снимка не можа да бъде заснета."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Екранната снимка не можа да бъде запазена. Възможно е хранилището да се използва."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Опции за пренос на файлове чрез USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Свързване като медиен плейър (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Свързване като камера (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ гост"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Изход от сесията като гост"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"За една минута"</item>
     <item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отваряне на настройките за режима за запазване на батерията"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Изход от сесията като гост"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ще започне да заснема всичко, което се показва на екрана ви."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Да не се показва отново"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Стартиране сега"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 0577ce2..7bdc06a 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"স্ক্রীনশট নেওয়া হযেছে৷"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"আপনার স্ক্রীনশট দেখতে স্পর্শ করুন৷"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"স্ক্রীনশট সংরক্ষণ করা যায়নি৷ সঞ্চয়স্থান ব্যবহারে থাকতে পারে৷"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ফাইল স্থানান্তরের বিকল্পগুলি"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"একটি মিডিয়া প্লেয়ার হিসাবে মাউন্ট করুন (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"একটি ক্যামেরা হিসাবে মাউন্ট করুন (PTP)"</string>
@@ -254,7 +255,7 @@
     <string name="zen_important_interruptions" msgid="3477041776609757628">"শুধুমাত্র প্রাধান্য বাধাগুলি"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"আপনার পরবর্তী অ্যালার্মের সময় <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"আপনার পরবর্তী অ্যালার্মের সময় <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
-    <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> বাজলে আপনার অ্যালার্ম শুনতে পাবেন না"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> বাজলে আপনি অ্যালার্ম শুনতে পাবেন না"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"নিচে অপেক্ষাকৃত কম জরুরী বিজ্ঞপ্তিগুলি"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"খোলার জন্য আবার আলতো চাপুন"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"অতিথি"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ অতিথি"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"অতিথির প্রস্থান"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"এক মিনিটের জন্য"</item>
     <item quantity="other" msgid="6924190729213550991">"%d মিনিটের জন্য"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ব্যাটারি সেভার সেটিংস খুলুন"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"অতিথির প্রস্থান"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> আপনার স্ক্রীনে দেখানো সব কিছু ক্যাপচার করা শুরু করবে।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"আর দেখাবেন না"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"এখন শুরু করুন"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index d651aaa..541d60d 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"S\'ha fet una captura de pantalla."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca per veure la captura de pantalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"No s\'ha pogut fer una captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"No s\'ha pogut desar la captura de pantalla. És possible que l\'emmagatzematge estigui en ús."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcions transf. fitxers USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Munta com a reproductor multimèdia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Munta com a càmera (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Convidat"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidat"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Surt del mode de convidat"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durant un minut"</item>
     <item quantity="other" msgid="6924190729213550991">"Durant %d minuts"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Obre la configuració de la funció Estalvi de bateria"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Surt del mode de convidat"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> començarà a enregistrar tot el que es mostri a la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No ho tornis a mostrar"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Comença ara"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c50e0e9..68b84a9 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky zachycen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímek obrazovky zobrazíte dotykem."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Snímek obrazovky se nepodařilo zachytit."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Snímek obrazovky se nepodařilo uložit. Je možné, že je externí úložiště právě používáno."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti přenosu souborů pomocí rozhraní USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Připojit jako přehrávač médií (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Připojit jako fotoaparát (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Host"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Přidat hosta"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončit relaci hosta"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Na jednu minutu"</item>
     <item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otevřít nastavení režimu Úspora baterie"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončit relaci hosta"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávat vše, co je zobrazeno na obrazovce."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Tuto zprávu příště nezobrazovat"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Spustit"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index de11049..f915332 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skærmbilledet er gemt."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Tryk for at se dit skærmbillede."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Skærmbilledet kunne ikke tages."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Skærmbilledet kunne ikke gemmes. Eksternt lager kan være i brug."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Muligheder for USB-filoverførsel"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Isæt som en medieafspiller (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Isæt som et kamera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gæst"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Gæst"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Forlad gæstesession"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"I ét minut"</item>
     <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åbn indstillinger for Batteribesparende"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Forlad gæstesession"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil begynde at optage alt, hvad der vises på din skærm."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start nu"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a57d3a7..d7213ba 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot aufgenommen"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Zum Ansehen berühren"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot konnte nicht aufgenommen werden."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Screenshot konnte nicht gespeichert werden. Eventuell wird der Speicher gerade verwendet."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-Dateiübertragungsoptionen"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Als Medienplayer (MTP) bereitstellen"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Als Kamera (PTP) bereitstellen"</string>
@@ -168,11 +169,11 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Fenster schließen"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Mehr Zeit"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Weniger Zeit"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-Daten sind deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-Daten sind deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilfunkdaten sind deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Daten sind deaktiviert"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Die Daten wurden auf Ihrem Gerät deaktiviert, da das von Ihnen festgelegte Limit erreicht wurde.\n\nWenn Sie die Daten erneut aktivieren, berechnet Ihr Mobilfunkanbieter möglicherweise Gebühren."</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-Daten deaktiviert"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-Daten deaktiviert"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilfunkdaten deaktiviert"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Daten deaktiviert"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Die Datennutzung wurde auf Ihrem Gerät deaktiviert, da das von Ihnen festgelegte Limit erreicht wurde.\n\nWenn Sie die Funktion erneut aktivieren, berechnet Ihr Mobilfunkanbieter möglicherweise Gebühren."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Daten aktivieren"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus beenden"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Für eine Minute"</item>
     <item quantity="other" msgid="6924190729213550991">"Für %d Minuten"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Einstellungen für den Energiesparmodus öffnen"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus beenden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf Ihrem Bildschirm angezeigten Aktivitäten auf."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Jetzt starten"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c913b72..c972a69 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Λήφθηκε το στιγμιότυπο οθόνης ."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Αγγίξτε για να δείτε το στιγμιότυπο οθόνης σας"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Αδύνατη η αποθήκευση του στιγμιότυπου οθόνης."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Αδύνατη η αποθήκευση στιγμιότυπου οθόνης. Ο εξωτερικός χώρος αποθήκευσης μπορεί να είναι σε χρήση."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Επιλογές μεταφοράς αρχείων μέσω USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Προσάρτηση ως μονάδας αναπαραγωγής μέσων (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Προσάρτηση ως κάμερας (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Επισκέπτης"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Επισκέπτης"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Έξοδος επισκέπτη"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Για ένα λεπτό"</item>
     <item quantity="other" msgid="6924190729213550991">"Για %d λεπτά"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Άνοιγμα ρυθμίσεων Εξοικονόμησης μπαταρίας"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Έξοδος επισκέπτη"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Θα ξεκινήσει η καταγραφή του περιεχομένου που εμφανίζεται στην οθόνη σας από την εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Να μην εμφανιστεί ξανά"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Έναρξη τώρα"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index b0981b1..e3fa73f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Couldn\'t save screenshot. Storage may be in use."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -223,7 +224,7 @@
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
-    <string name="quick_settings_done" msgid="3402999958839153376">"Finished"</string>
+    <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
     <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index b0981b1..e3fa73f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Couldn\'t save screenshot. Storage may be in use."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -223,7 +224,7 @@
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
-    <string name="quick_settings_done" msgid="3402999958839153376">"Finished"</string>
+    <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
     <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Exit guest"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e69eec9..078eb86 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Se guardó la captura de pantalla."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver tu captura de pantalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"No se pudo guardar la captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"No se pudo guardar la captura de pantalla. Puede que el almacenamiento esté en uso."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Agregar invitado"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configuración del ahorro de batería"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comenzará la captura de todo lo que se muestre en la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Comenzar ahora"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 48fe8de..a4311b4 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura guardada"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver la captura de pantalla"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"No se ha podido guardar la captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"No se ha podido guardar la captura de pantalla. Puede que el almacenamiento esté en uso."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Añadir invitado"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir ajustes de la función de ahorro de batería"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Salir de modo invitado"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar ahora"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 10fdd06..01196bb 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekraanipilt on jäädvustatud."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Puudutage kuvatõmmise vaatamiseks."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvatõmmist ei saanud jäädvustada."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Kuvatõmmist ei saa salvestada. Mäluseade võib olla kasutuses."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-failiedastuse valikud"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Paigalda meediumimängijana (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Paigalda kaamerana (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Külaline"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ külaline"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Välju külastaja režiimist"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Üheks minutiks"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minutiks"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ava akusäästja seaded"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Välju külastaja režiimist"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> hakkab jäädvustama kõike, mida ekraanil kuvatakse."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ära kuva uuesti"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Alusta kohe"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index ddeadd9..15a96e0 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Pantaila-argazkia atera da."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Pantaila-argazkia ikusteko, ukitu ezazu."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Ezin izan da pantaila-argazkia atera."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Ezin izan da pantaila-argazkia gorde. Baliteke memoria erabiltzen aritzea."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB fitxategiak transferitzeko aukerak"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Muntatu multimedia-erreproduzigailu gisa (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Muntatu kamera gisa (PTP)"</string>
@@ -191,7 +192,7 @@
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetootha"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetootha (<xliff:g id="NUMBER">%d</xliff:g> gailu)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetootha desaktibatuta"</string>
-    <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Ez dago bikotetutako gailurik erabilgarri"</string>
+    <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Ez dago parekatutako gailurik erabilgarri"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Distira"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Biratze automatikoa"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Biratzea blokeatuta"</string>
@@ -213,8 +214,8 @@
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ez dago sarerik"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi konexioa desaktibatuta"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Ez dago gordetako sarerik erabilgarri"</string>
-    <string name="quick_settings_cast_title" msgid="1893629685050355115">"Igorri pantaila"</string>
-    <string name="quick_settings_casting" msgid="6601710681033353316">"Igorpena"</string>
+    <string name="quick_settings_cast_title" msgid="1893629685050355115">"Igorri pantailako edukia"</string>
+    <string name="quick_settings_casting" msgid="6601710681033353316">"Igortzen"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Izenik gabeko gailua"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Igortzeko prest"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Ez dago gailurik erabilgarri"</string>
@@ -236,7 +237,7 @@
     <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Mugaren gainetik"</string>
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> erabilita"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Muga: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> abisua"</string>
+    <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="7883614615463619450">"Ez dago azkenaldian erabilitako aplikaziorik"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string>
     <string name="recents_lock_to_app_button_label" msgid="4793991421811647489">"aplikazio bakarreko modua"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gonbidatua"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Gonbidatua"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Irten gonbidatuen modutik"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Minutu batez"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minutuz"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ireki bateria aurrezlearen ezarpenak"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"%% <xliff:g id="LEVEL">%d</xliff:g>"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Irten gonbidatuen modutik"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak pantailan bistaratzen den guztia grabatuko du."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ez erakutsi berriro"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Hasi"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index c864170..73a5800 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"تصویر صفحه گرفته شد."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"برای مشاهده تصویر صفحه خود، لمس کنید."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"تصویر صفحه گرفته نشد."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"تصویر صفحه ذخیره نشد. ممکن است دستگاه ذخیره‌ در حال استفاده باشد."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"‏گزینه‌های انتقال فایل USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏نصب به‌عنوان دستگاه پخش رسانه (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏تصب به‌عنوان دوربین (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"مهمان"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ مهمان"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"خروج مهمان"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"برای یک دقیقه"</item>
     <item quantity="other" msgid="6924190729213550991">"‏برای %d دقیقه"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"باز کردن تنظیمات ذخیره کننده باتری"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>٪٪"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"خروج مهمان"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع به ضبط هر چیزی می‌کند که در صفحه‌نمایش شما نمایش داده می‌شود."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"دوباره نشان داده نشود"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"اکنون شروع شود"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index e1d4661..00431fa 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvakaappaus tallennettu"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Katso kuvakaappaus koskettamalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvakaappausta ei voitu tallentaa"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Kuvakaappauksen tallennus epäonnistui. Ulkoinen tallennustila voi olla käytössä."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-tiedostonsiirtoasetukset"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Käytä mediasoittimena (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Käytä kamerana (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Vieras"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Vieras"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Kirjaa vieras ulos"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Minuutiksi"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minuutiksi"</item>
@@ -283,7 +297,6 @@
     <!-- no translation found for battery_level_template (1609636980292580020) -->
     <skip />
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Kirjaa vieras ulos"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkaa tallentaa kaiken näytölläsi näkyvän."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Älä näytä uudelleen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Aloita nyt"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index d92f0fb..085d0b3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Impossible enregistrer capture d\'écran. Périphérique de stockage peut-être en cours d\'utilisation."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Installer comme un lecteur multimédia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Installer comme un appareil photo (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Déconnecter l\'invité"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
     <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres d\'économie d\'énergie"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Déconnecter l\'invité"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> commencer à enregistrer tout ce qui s\'affiche sur votre écran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Commencer maintenant"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 61acdd5..003168a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Impossible enregistrer capture d\'écran. Périphérique de stockage peut-être en cours d\'utilisation."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Installer en tant que lecteur multimédia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Installer en tant qu\'appareil photo (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Quitter le mode Invité"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
     <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres de l\'économiseur de batterie"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Quitter le mode Invité"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va commencer à capturer tous les contenus affichés à l\'écran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Commencer"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index ca0df92..7e3b441 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de pantalla gardada."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver a captura de pantalla."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Non se puido facer a captura de pantalla."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Non se puido gardar a captura de pantalla. É posible que o almacenamento estea en uso."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcións de transferencia USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Inserir como reprodutor multimedia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Inserir como cámara (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidado"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Retirar invitado"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir a configuración do aforrador de batería"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Retirar invitado"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comezará a capturar todo o que apareza na túa pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrar outra vez"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar agora"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 86877c7..b1ac437 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"स्‍क्रीनशॉट कैप्‍चर किया गया."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"अपना स्‍क्रीनशॉट देखने के लिए स्‍पर्श करें."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रीनशॉट को कैप्चर नहीं किया जा सका."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"स्‍क्रीनशॉट को सहेजा नहीं जा सका. संभवत: संग्रहण उपयोग में है."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB फ़ाइल स्थानांतरण विकल्प"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेयर के रूप में माउंट करें (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"कैमरे के रूप में माउंट करें (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूर्ण होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> शेष)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"अतिथि"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ अतिथि"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"अतिथि मोड से बाहर निकलें"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"एक मिनट के लिए"</item>
     <item quantity="other" msgid="6924190729213550991">"%d मिनट के लिए"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"बैटरी सेवर सेटिंग चालू करें"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"अतिथि मोड से बाहर निकलें"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपके स्क्रीन पर प्रदर्शित प्रत्येक सामग्री को कैप्चर करना प्रारंभ कर देगी."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"फिर से न दिखाएं"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"अब प्रारंभ करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 1d586e1..6e34b35 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Zaslon je snimljen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite za prikaz snimke zaslona."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nije bilo moguće snimiti zaslon."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Nije bilo moguće spremiti snimku zaslona. Možda se upotrebljava pohrana."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa datoteka"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Učitaj kao media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Učitaj kao fotoaparat (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ gost"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Izlaz iz gostujućeg načina"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item>
     <item quantity="other" msgid="6924190729213550991">"%d min"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvaranje postavki štednje baterije"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Izlaz iz gostujućeg načina"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> počet će snimati sve što se prikazuje na zaslonu."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Započni sad"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index e9f6c29..f3e8025 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Képernyőkép rögzítve."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Megérintésével megtekintheti a képernyőképet."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nem sikerült rögzíteni a képernyőképet."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Nem lehet menteni a képernyőképet. Lehet, hogy a tároló használatban van."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB-fájlátvitel beállításai"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Csatlakoztatás médialejátszóként (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Csatlakoztatás kameraként (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Vendég"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ vendég"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Vendég kiléptetése"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Egy percen át"</item>
     <item quantity="other" msgid="6924190729213550991">"%d percen át"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Akkumulátorkímélő mód beállításainak megnyitása"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>. szint"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalomjegyzék elrejtve"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Vendég kiléptetése"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Indítás most"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 0ff2136..813b253 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Էկրանի հանույթը լուսանկարվել է:"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Հպեք ձեր էկրանի հանույթը տեսնելու համար:"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Չհաջողվեց լուսանկարել էկրանի հանույթը:"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Չհաջողվեց պահել էկրանի հանույթը: Հնարավոր է` պահոցն օգտագործման մեջ է:"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ֆայլերի փոխանցման ընտրանքներ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Միացնել որպես մեդիա նվագարկիչ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Միացնել որպես ֆոտոխցիկ (PTP)"</string>
@@ -166,18 +167,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Փակել վահանակը"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Ավելացնել ժամանակը"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Քչացնել ժամանակը"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G տվյալների կապն անջատված է"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G տվյալների կապն անջատված է"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Բջջային տվյալներն անջատված են"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Տվյալների կապն անջատված է"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Տվյալների կապը ձեր սարքում անջատվեց, քանի որ դուք հատել եք նշված սահմանաչափը:\n\nԱյն հետ միացնելուց հետո հնարավոր են հավելյալ վճարներ ձեր օպերատորից:"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Միացնել տվյալների կապը"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Որոնում է GPS"</string>
@@ -255,16 +250,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Սահեցրեք ձախ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Առանց ընդհատումների՝ ներառյալ զարթուցիչները"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Առանց ընդհատումների"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Միայն կարևոր ընդհատումներ"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"Ձեր հաջորդ զարթուցիչի ժամն է՝ <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Ձեր հաջորդ զարթուցիչի օրն է՝ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"Դուք չեք լսի ձեր զարթուցիչը <xliff:g id="ALARM_TIME">%s</xliff:g>-ին:"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Պակաս հրատապ ծանուցումները ստորև"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Կրկին հպեք՝ բացելու համար"</string>
@@ -278,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Հյուր"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Հյուր"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Դուրս գալ հյուրի ռեժիմից"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Մեկ րոպե"</item>
     <item quantity="other" msgid="6924190729213550991">"%d րոպե"</item>
@@ -291,12 +295,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Բացել մարտկոցի տնտեսման կարգավորումները"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ծրագիրը կսկսի հավաքագրել այն ամենն ինչ ցուցադրվում է ձեր էկրանին:"</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Այլևս ցույց չտալ"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"Մեկնարկել հիմա"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 8e39734..80df525 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan layar diambil."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan layar Anda."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat mengambil tangkapan layar."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Tidak dapat menyimpan tangkapan layar. Penyimpanan mungkin sedang digunakan."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opsi transfer file USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pasang sebagai pemutar media (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Pasang sebagai kamera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Tamu"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Tamu"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Keluar dari tamu"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item>
     <item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka setelan penghemat baterai"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Keluar dari tamu"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mulai menangkap apa saja yang ditampilkan pada layar Anda."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tampilkan lagi"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Mulai sekarang"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 7378dff..adae78d 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skjámynd var tekin."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snertu til að skoða skjámyndina."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Ekki tókst að taka skjámynd."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Ekki tókst að vista skjámynd. Geymslan kann að vera í notkun."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Valkostir USB-skráaflutnings"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Tengja sem efnisspilara (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Tengja sem myndavél (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gestur"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Gestur"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Loka gestastillingu"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Í eina mínútu"</item>
     <item quantity="other" msgid="6924190729213550991">"Í %d mínútur"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Opna stillingar rafhlöðusparnaðar"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Loka gestastillingu"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mun fanga allt sem birtist á skjánum."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ekki sýna þetta aftur"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Byrja núna"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f813cdf..8c87056 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot acquisito."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Tocca per visualizzare il tuo screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Impossibile acquisire lo screenshot."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Impossibile salvare lo screenshot. L\'archivio esterno potrebbe essere in uso."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opzioni trasferimento file USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Monta come lettore multimediale (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Monta come videocamera (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Ospite"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ ospite"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Esci dalla modalità ospite"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Per un minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Per %d minuti"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Apri impostazioni risparmio batteria"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Esci dalla modalità ospite"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inizierà ad acquisire tutto ciò che è visualizzato sul tuo schermo."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Non·mostrare·più"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Avvia adesso"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index d0151bb..f5d67f3 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"צילום המסך בוצע."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"גע כדי להציג את צילום המסך שלך"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"לא ניתן לבצע צילום מסך."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"לא ניתן לשמור את צילום המסך. ייתכן שנעשה שימוש באמצעי אחסון."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"‏אפשרויות העברת קבצים ב-USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏טען כנגן מדיה (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏טען כמצלמה (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"אורח"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ אורח"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"צא ממצב אורח"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"למשך דקה אחת"</item>
     <item quantity="other" msgid="6924190729213550991">"‏למשך %d דקות"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"פתח את ההגדרות של \'חיסכון בסוללה\'"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"צא ממצב אורח"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> יתחיל להקליט את כל התוכן המוצג במסך שלך."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"אל תציג שוב"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"התחל כעת"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 90d648d..060a565 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"スクリーンショットを取得しました。"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"タップしてスクリーンショットを表示します。"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"スクリーンショットをキャプチャできませんでした。"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"スクリーンショットを保存できませんでした。ストレージが使用中の可能性があります。"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USBファイル転送オプション"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"メディアプレーヤー(MTP)としてマウント"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"カメラ(PTP)としてマウント"</string>
@@ -253,7 +254,7 @@
     <string name="description_direction_left" msgid="7207478719805562165">"左にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
     <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"サイレント(アラームなど)"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"サイレント"</string>
-    <string name="zen_important_interruptions" msgid="3477041776609757628">"優先的な中断のみ"</string>
+    <string name="zen_important_interruptions" msgid="3477041776609757628">"重要な通知のみ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"次のアラームは<xliff:g id="ALARM_TIME">%s</xliff:g>です"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"次のアラームは<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>です"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g>のアラームは鳴りません"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ ゲスト"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"ゲストを終了"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1分"</item>
     <item quantity="other" msgid="6924190729213550991">"%d分"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"バッテリーセーバーの設定を開く"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"ゲストを終了"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>で、画面に表示されているコンテンツのキャプチャを開始します。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"次回から表示しない"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"今すぐ開始"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index b9f24ec..a99730c 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"სკრინშოტი გადაღებულია."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"შეეხეთ ეკრანის სურათის სანახავად."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ვერ მოხერხდა ეკრანის ანაბეჭდის გადაღება."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"ეკრანის სურათი ვერ შეინახა. შესაძლოა, მეხსიერება უკვე დაკავებულია."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ფაილის ტრანსფერის პარამეტრები"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"მედია-საკრავად (MTP) ჩართვა"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"მიუერთეთ როგორც კამერა (PTP)"</string>
@@ -166,18 +167,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"არეს დახურვა"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"მეტი დრო"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"ნაკლები დრო"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G მონაც. გადაცემა გამორთულია"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G მონაც. გადაცემა გამორთულია"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ფიჭური ინტერნეტი გამორთულია"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"მონაცემთა გადაცემა გამორთულია"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"თქვენმა მოწყობილობამ მონაცემები გამორთო, რადგან თქვენ მიერ დაყენებულ ლიმიტს მიაღწია.\n\nმისი კვლავ გააქტიურებით შესაძლოა დაგეკისროთ გადასახადი თქვენი ოპერატორისგან."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"მონაცემთა ჩართვა"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-ის ძებნა"</string>
@@ -218,7 +213,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"არ არის დაკავშირებული."</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ქსელი არ არის"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi გამორთულია"</string>
-    <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"შენახუი ქსელები მიუწვდომელია"</string>
+    <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"შენახული ქსელები მიუწვდომელია"</string>
     <string name="quick_settings_cast_title" msgid="1893629685050355115">"ეკრანის გადაცემა"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"გადაიცემა"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"უსახელო მოწყობილობა"</string>
@@ -255,16 +250,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"გაასრიალეთ მარცხნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"შეწყვეტების გარეშე, მაღვიძარების ჩათვლით"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"შეწყვეტების გარეშე"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"მხოლოდ პრიორიტეტული შეწყვეტები"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"თქვენი შემდეგი მაღვიძარაა <xliff:g id="ALARM_TIME">%s</xliff:g>-ზე"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"თქვენი შემდეგი მაღვიძარაა <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"თქვენს მაღვიძარას <xliff:g id="ALARM_TIME">%s</xliff:g>-ზე ვერ გაიგონებთ"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ქვემოთ მითითებულია ნაკლებად სასწრაფო შეტყობინებები"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"შეეხეთ ისევ გასახსნელად"</string>
@@ -278,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"სტუმარი"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ სტუმარი"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"სტუმრის გასვლა"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ერთი წუთით"</item>
     <item quantity="other" msgid="6924190729213550991">"%d წუთით"</item>
@@ -291,12 +295,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ბატარეის დამზოგის პარამეტრების გახსნა"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> დაიწყებს იმ ყველაფრის აღბეჭდვას, რაც თქვენს ეკრანზე ჩანს."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"აღარ მაჩვენო"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"დაწყება ახლავე"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index a3505a3..de114d2 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сақталды."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Скриншотты көру үшін түрту."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот жасалмады."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Скриншотты сақтай алмады. Жад қолданыста болуы мүмкін."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB файлын жіберу опциялары"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойнатқыш (MTP) ретінде қосыңыз"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Камера ретінде (PTP) қосыңыз"</string>
@@ -166,18 +167,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Тақтаны жабу"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Көбірек уақыт"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Азырақ уақыт"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G деректері өшірулі"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G деректері өшірулі"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Ұялы деректер өшірулі"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Деректер өшірулі"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Құрылғыңыз сіз орнатқан шекке жеткендіктен деректерді өшірді.\n\nОны қайтадан қосу оператордың ақылар алуына әкелуі мүмкін."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Деректерді қосу"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS қызметін іздеуде"</string>
@@ -255,16 +250,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"Іздеу"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үшін жоғары сырғыту."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үшін солға сырғыту."</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Үзілістерсіз, соның ішінде, дабылдарсыз"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Үзулерсіз"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Тек басым үзулер"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"Келесі дабыл — <xliff:g id="ALARM_TIME">%s</xliff:g> уақытында"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Келесі дабыл — <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> уақытында дабылды естімейсіз"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Шұғылдығы азырақ хабарландырулар төменде"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ашу үшін қайта түртіңіз"</string>
@@ -278,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Қонақ"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Қонақ"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Қонақтан шығу"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Бір минут бойы"</item>
     <item quantity="other" msgid="6924190729213550991">"%d минут бойы"</item>
@@ -291,12 +295,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батарея үнемдегіш параметрлерін ашу"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранда көрсетілгеннің барлығын түсіре бастайды."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Қайта көрсетпеу"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"Қазір бастау"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 6b2d46d..0ac6f40 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"បាន​ចាប់​យក​រូបថត​អេក្រង់។​"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"ប៉ះ ​ដើម្បី​មើល​រូបថត​អេក្រង់​របស់​អ្នក​។"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"មិន​អាច​ចាប់​យក​រូប​ថត​អេក្រង់​។"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"មិន​អាច​រក្សាទុក​រូបថត​អេក្រង់​។ ឧបករណ៍​ផ្ទុក​អាច​កំពុង​ប្រើ​​។"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"ជម្រើស​ផ្ទេរ​ឯកសារ​តាម​យូអេសប៊ី"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ភ្ជាប់​ជា​កម្មវិធី​ចាក់​មេឌៀ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ភ្ជាប់​ជា​ម៉ាស៊ីន​ថត (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុង​បញ្ចូល​ថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើប​ពេញ)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"ភ្ញៀវ"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ ភ្ញៀវ"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"ភ្ញៀវ​ចាកចេញ"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"សម្រាប់​មួយ​នាទី"</item>
     <item quantity="other" msgid="6924190729213550991">"សម្រាប់ %d នាទី"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"បើក​ការ​កំណត់​កម្មវិធី​សន្សំ​ថ្ម"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"បាន​លាក់​មាតិកា"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"ភ្ញៀវ​ចាកចេញ"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹង​ចាប់ផ្ដើម​ចាប់​យក​អ្វីៗ​គ្រប់យ៉ាង​ដែល​បង្ហាញ​លើ​អេក្រង់​របស់​អ្នក។"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"កុំ​បង្ហាញ​ម្ដងទៀត"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ចាប់ផ្ដើម​ឥឡូវ"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 2c58be6..d89687e 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ವೀಕ್ಷಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಸೆರೆಹಿಡಿಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಸಂಗ್ರಹಣೆಯು ಬಳಕೆಯಲ್ಲಿರಬಹುದು."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ಫೈಲ್ ವರ್ಗಾವಣೆ ಆಯ್ಕೆಗಳು"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ಮೀಡಿಯಾ ಪ್ಲೇಯರ್ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ಕ್ಯಾಮರಾ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"ಅತಿಥಿ"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ ಅತಿಥಿ"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"ಅತಿಥಿ ಅನ್ನು ನಿರ್ಗಮಿಸಿ"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ಒಂದು ನಿಮಿಷದವರೆಗೆ"</item>
     <item quantity="other" msgid="6924190729213550991">"%d ನಿಮಿಷಗಳವರೆಗೆ"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ಬ್ಯಾಟರಿ ರಕ್ಷಕದ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"ಅತಿಥಿ ಅನ್ನು ನಿರ್ಗಮಿಸಿ"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"ನಿಮ್ಮ ಪರದೆಯ ಮೇಲೆ ಪ್ರದರ್ಶಿಸಲಾಗುವ ಎಲ್ಲವನ್ನೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಯು ಸೆರೆಹಿಡಿಯಲು ಪ್ರಾರಂಭಿಸುತ್ತದೆ."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸದಿರಿ"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4e05e9c..f2488f6 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -75,7 +75,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"캡쳐화면 저장됨"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"캡쳐화면을 보려면 터치하세요."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"캡쳐화면을 캡쳐하지 못했습니다."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"캡쳐화면을 저장할 수 없습니다. 저장소를 사용 중인 것 같습니다."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 파일 전송 옵션"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"미디어 플레이어로 마운트(MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"카메라로 마운트(PTP)"</string>
@@ -172,7 +173,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 데이터 사용 중지됨"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"이동통신 데이터 사용 중지됨"</string>
     <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"기기가 설정 한도에 도달하여 데이터를 사용 중지했습니다.\n\n데이터를 다시 사용 설정하면 이동통신사로부터 대금이 청구될 수 있습니다."</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"데이터가 설정 한도에 도달하여 사용 중지되었습니다.\n\n데이터를 다시 사용 설정하면 이동통신사로부터 대금이 청구될 수 있습니다."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"데이터 사용 설정"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"손님"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"새 손님 추가"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"손님 모드 종료"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1분 동안"</item>
     <item quantity="other" msgid="6924190729213550991">"%d분 동안"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"배터리 세이버 설정 열기"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"손님 모드 종료"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 화면에 표시된 모든 것을 캡처하기 시작합니다."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"다시 표시 안함"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"시작하기"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 9f6892c..0d6867c 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -96,7 +96,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот тартылды."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Тийип, скриншотту көрүңүз."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот кылынбай жатат."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Скриншот сакталбай жатат. Сактагыч пайдаланууда болушу мүмкүн."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <!-- no translation found for usb_preference_title (6551050377388882787) -->
     <skip />
     <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
@@ -192,18 +193,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Тактаны жабуу"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Көбүрөөк убакыт"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Азыраак убакыт"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2Гб-3Гб көлөмдөгү дайындар өчүрүлдү."</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4Гб көлөмдөгү дайындар өчүрүлдү"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Уюктук дайындар тармагы өчүк"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дайындарды кабыл алуу өчүрүлгөн."</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Белгиленген эң жогорку чекке жеткендиктен, түзмөгүңүз дайындарды кабыл алууну токтотту.\n\nДайындарды кабыл алууну улантам десеңиз, операторго акы төлөп калышыңыз мүмкүн."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Дайындарды алууну иштетүү"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS издөө"</string>
@@ -281,16 +276,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"Издөө"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үчүн жогору жылмыштырыңыз."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үчүн солго жылмыштырыңыз."</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Үзгүлтүктөр, ошондой эле үн ишараттары болбойт"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Үзгүлтүксүз"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Артыкчылыктуу үзгүлтүктөр гана"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"Кийинки үн ишараты саат <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Кийинки үн ишараты <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"Саат <xliff:g id="ALARM_TIME">%s</xliff:g> үн ишаратын укпайсыз."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Анчейин шашылыш эмес эскертмелер төмөндө"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ачуу үчүн кайра таптап коюңуз"</string>
@@ -304,6 +295,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Конок"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Конок"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Конок режиминен чыгуу"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Бир мүнөткө"</item>
     <item quantity="other" msgid="6924190729213550991">"%d мүнөткө"</item>
@@ -317,12 +321,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батареяны үнөмдөгүчтүн жөндөөлөрүн ачуу"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранга чыккан нерсенин баарын сүрөткө тарта баштайт."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Экинчи көрсөтүлбөсүн"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"Азыр баштоо"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index ef98cca..83ace48 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"ຖ່າຍຮູບໜ້າຈໍແລ້ວ"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"ແຕະເພື່ອເບິ່ງພາບໜ້າຈໍຂອງທ່ານ."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"ບໍ່ສາມາດບັນທຶກພາບໜ້າຈໍໄດ້. ບ່ອນຈັດເກັບອາດກຳລັງຖືກນຳໃຊ້ຢູ່."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ໂຕເລືອກການຍ້າຍໄຟລ໌"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ເຊື່ອມຕໍ່ເປັນ media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ເຊື່ອມຕໍ່ເປັນກ້ອງຖ່າຍຮູບ (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"ແຂກ"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ ແຂກ"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"​ອອກ​ຈາກ​ຜູ່​ມາ​ຢາມ"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ເປັນ​ເວລາ​ນຶ່ງ​ນາ​ທີ"</item>
     <item quantity="other" msgid="6924190729213550991">"ເປັນ​ເວລາ %d ນາ​ທີ"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ເປີດ​ການ​ຕັ້ງຄ່າ​ໂຕ​ປະຢັດ​ແບັດເຕີຣີ"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"​ເນື້ອ​ຫາ​ຖືກ​ເຊື່ອງ​ແລ້ວ"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"​ອອກ​ຈາກ​ຜູ່​ມາ​ຢາມ"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ​ຈະ​ເລີ່ມ​ບັນ​ທຶກ​ທຸກ​ຢ່າງ​ທີ່​ສະ​ແດງ​ຜົນ​ໃນ​ໜ້າ​ຈໍ​ທ່ານ."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ບໍ່​ຕ້ອງ​ສະ​ແດງ​ອີກ"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ເລີ່ມດຽວນີ້"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index bdbcf64..567aa00 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrano kopija užfiksuota."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Palieskite, kad peržiūrėtumėte ekrano kopiją."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nepavyko užfiksuoti ekrano kopijos."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Nepavyko išsaugoti ekrano kopijos. Gali būti naudojama atmintis."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB failo perdavimo parinktys"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos leistuvę (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Įmontuoti kaip fotoaparatą (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Svečias"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Svečias"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Išeiti iš svečio režimo"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 min."</item>
     <item quantity="other" msgid="6924190729213550991">"%d min."</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atidaryti akumuliatoriaus tausojimo priemonės nustatymus"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Išeiti iš svečio režimo"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ pradės fiksuoti viską, kas rodoma jūsų ekrane."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Daugiau neberodyti"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Pradėti dabar"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index cf3996a..3eb35aa 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrānuzņēmums ir uzņemts."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Pieskarieties, lai skatītu ekrānuzņēmumu."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nevarēja uzņemt ekrānuzņēmumu."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Nevarēja saglabāt ekrānuzņēmumu. Iespējams, tiek izmantota atmiņa."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB failu pārsūtīšanas opcijas"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pievienot kā multivides atskaņotāju (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Pievienot kā kameru (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Viesis"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+Viesis"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Iziet no viesa režīma"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Vienu minūti"</item>
     <item quantity="other" msgid="6924190729213550991">"%d min"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atvērt akumulatora enerģijas taupīšanas režīma iestatījumus"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Iziet no viesa režīma"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sāks uzņemt visu, kas tiks rādīts jūsu ekrānā."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vairs nerādīt"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Sākt tūlīt"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 803e028..39021ca 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Сликата на екранот е снимена."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Допрете за да ја видите сликата на екранот."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Сликата на екранот не можеше да се сними."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Сликата на екранот не можеше да се зачува. Можеби меморијата е во употреба."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Пренос на датотека со УСБ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Монтирај како мултимедијален плеер (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Монтирај како фотоапарат (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Гостин"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ гостин"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Излези како гостин"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"За една минута"</item>
     <item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отвори ги поставките за штедачот на батерија"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Излези како гостин"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе започне да презема сѐ што се прикажува на вашиот екран."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Не покажувај повторно"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Започни сега"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 663aa35..61f949b 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"സ്‌ക്രീൻഷോട്ട് എടുത്തു."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"നിങ്ങളുടെ സ്‌ക്രീൻഷോട്ട് കാണാനായി സ്‌പർശിക്കുക."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"സ്‌ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കാൻ കഴിഞ്ഞില്ല. സംഭരണം ഉപയോഗത്തിലായിരിക്കാം."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ഫയൽ കൈമാറൽ ഓപ്‌ഷനുകൾ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ഒരു മീഡിയ പ്ലേയറായി (MTP) മൗണ്ടുചെയ്യുക"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ഒരു ക്യാമറയായി (PTP) മൗണ്ടുചെയ്യുക"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"അതിഥി"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ അതിഥി"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ഒരു മിനിറ്റ് ദൈർഘ്യം"</item>
     <item quantity="other" msgid="6924190729213550991">"%d മിനിറ്റ് ദൈർഘ്യം"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ബാറ്ററി സേവർ ക്രമീകരണങ്ങൾ തുറക്കുക"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്‌റ്റുകൾ മറച്ചു"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"അതിഥി മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"നിങ്ങളുടെ സ്ക്രീനിൽ പ്രദർശിപ്പിച്ചിരിക്കുന്ന എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ക്യാപ്‌ചർ ചെയ്യുന്നത് ആരംഭിക്കും."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"വീണ്ടും കാണിക്കരുത്"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ഇപ്പോൾ ആരംഭിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index e4d3222..2149df3 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Дэлгэцийн агшинг авсан."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Дэлгэцийн агшныг харах бол хүрнэ үү."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Дэлгэцийн агшинг авч чадсангүй."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Дэлгэцийн агшинг хадгалж чадсангүй. Сан ашиглагдаж байгаа бололтой."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB файл шилжүүлэх сонголт"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа тоглуулагч(MTP) болгон залгах"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Камер болгон(PTP) залгах"</string>
@@ -268,6 +269,13 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Зочин"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Зочин"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Зочноос гарах"</string>
+    <string name="guest_exit_guest_dialog_title" msgid="7587460301980067285">"Зочны нэвтрэлтээс гарч байна уу?"</string>
+    <string name="guest_exit_guest_dialog_message" msgid="10255285459589280">"Зочны нэвтрэлтээс гарснаар локал датаг арилгах болно."</string>
+    <string name="guest_wipe_session_title" msgid="6419439912885956132">"Тавтай морилно уу!"</string>
+    <string name="guest_wipe_session_message" msgid="5369763062345463297">"Та шинээр нэвтрэх гэж байна уу?"</string>
+    <string name="guest_wipe_session_wipe" msgid="9154291314115781448">"Тийм"</string>
+    <string name="guest_wipe_session_dontwipe" msgid="850084868661344050">"Үгүй, баярлалаа"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Нэг минутын турш"</item>
     <item quantity="other" msgid="6924190729213550991">"%d минутын турш"</item>
@@ -281,7 +289,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батерей хэмнэгчийн тохиргоог нээх"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Зочноос гарах"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> таны дэлгэц дээр гаргасан бүх зүйлийн зургийг авч эхэлнэ."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Дахиж үл харуулах"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Одоо эхлүүлэх"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 36e2caa..4e6914d 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रीनशॉट कॅप्चर केला."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"आपला स्क्रीनशॉट पाहण्यासाठी स्पर्श करा."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रीनशॉट कॅप्चर करू शकलो नाही."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"स्क्रीनशॉट जतन करू शकलो नाही. संचयन वापरात असू शकते."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB फाईल स्थानांतरण पर्याय"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेअर म्हणून माउंट करा (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"कॅमेरा म्हणून माउंट करा (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"अतिथी"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ अतिथी"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"निर्गमन करणारे अतिथी"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"एक मिनिटासाठी"</item>
     <item quantity="other" msgid="6924190729213550991">"%d मिनिटांसाठी"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"बॅटरी बचतकर्ता सेटिंग्‍ज उघडा"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"निर्गमन करणारे अतिथी"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपल्‍या स्‍क्रीनवर प्रदर्शित होणारी प्रत्‍येक गोष्‍ट कॅप्‍चर करणे प्रारंभ करेल."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"पुन्हा दर्शवू नका"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"आता प्रारंभ करा"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 543f0f9..3e5e3c3 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan skrin ditangkap."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan skrin anda."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat menangkap tangkapan skrin."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Tidak boleh menyimpan tangkapan skrin. Storan mungkin sedang digunakan."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Pilihan pemindahan fail USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Lekapkan sebagai pemain media (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Lekapkan sebagai kamera (PTP)"</string>
@@ -166,18 +167,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Tutup panel"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Lagi masa"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Kurang masa"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G-3G dimatikan"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G dimatikan"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data selular dimatikan"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data dimatikan"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Peranti anda mematikan data kerana telah mencapai had yang anda tetapkan.\n\nMenghidupkan data semula boleh menyebabkan anda dikenakan caj oleh pembawa anda."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Hidupkan data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Mencari GPS"</string>
@@ -220,7 +215,7 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Dimatikan"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Tiada rangkaian disimpan tersedia"</string>
     <string name="quick_settings_cast_title" msgid="1893629685050355115">"Skrin Cast"</string>
-    <string name="quick_settings_casting" msgid="6601710681033353316">"Barisan Pelakon"</string>
+    <string name="quick_settings_casting" msgid="6601710681033353316">"Menghantar"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Peranti tidak bernama"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Bersedia untuk menghantar"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Tiada peranti tersedia"</string>
@@ -242,7 +237,7 @@
     <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Melebihi had"</string>
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> digunakan"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> had"</string>
-    <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> amaran"</string>
+    <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="7883614615463619450">"Tiada apl terbaharu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
     <string name="recents_lock_to_app_button_label" msgid="4793991421811647489">"kunci ke apl"</string>
@@ -255,16 +250,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Luncurkan ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Tiada gangguan, termasuk penggera"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Tiada gangguan"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Gangguan keutamaan sahaja"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"Penggera anda yang seterusnya pada <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Penggera anda yang seterusnya pada <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"Anda tdk akan mdgr penggera anda pd <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Pemberitahuan kurang penting di bawah"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ketik lagi untuk membuka"</string>
@@ -278,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Tetamu"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Tetamu"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Tetamu keluar"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Selama satu minit"</item>
     <item quantity="other" msgid="6924190729213550991">"Selama %d minit"</item>
@@ -291,12 +295,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka tetapan penjimat bateri"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mula mengabadikan semua yang dipaparkan pada skrin anda.."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tunjukkan lagi"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"Mulakan sekarang"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 9f06442..7176c34 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -71,7 +71,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား ဖမ်းယူပြီး"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"သင့်ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား ကြည့်ရှုရန် ထိပါ"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား မဖမ်းစီးနိုင်ပါ"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား မသိမ်းဆည်းနိုင်ပါ သိမ်းဆည်းမှုအား အသုံးပြုနေပါလိမ့်မည်"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ဖိုင်ပြောင်း ရွေးမှုများ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"မီဒီယာပလေရာအနေဖြင့် တပ်ဆင်ရန် (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ကင်မရာအနေဖြင့် တပ်ဆင်ရန် (PTP)"</string>
@@ -266,6 +267,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"ဧည့်သည်"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ ဧည့်သည်"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"ဧည့်သည့် ထွက်ရန်"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"တစ်မိနစ် အတွင်း"</item>
     <item quantity="other" msgid="6924190729213550991">"%d မိနစ် အတွင်း"</item>
@@ -277,7 +291,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ဘက်ထရီ ချွေတာသူ ဆက်တင်များကို ဖွင့်ရန်"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"ဧည့်သည့် ထွက်ရန်"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> က သင်၏ မျက်နှာပြင် ပေါ်မှာ ပြသထားသည့် အရာတိုင်းကို စတင် ဖမ်းယူမည်။"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"နောက်ထပ် မပြပါနှင့်"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ယခု စတင်ပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 587e119..f3d78bc 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skjermdumpen er lagret."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Trykk for å se skjermdumpen."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kan ikke lagre skjermdumpen."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan ikke ikke lagre skjermdumpen. Det er mulig ekstern lagring er i bruk."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Altern. for USB-filoverføring"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Sett inn som mediespiller (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Sett inn som kamera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gjest"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Gjest"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Avslutt gjesteøkten"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"I ett minutt"</item>
     <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åpen innstilling for batterisparing"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Avslutt gjesteøkten"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar opp alt som vies på skjermen din."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ikke vis igjen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start nå"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index baefb81..d1631ff 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रिनसट क्याप्चर गरियो।"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"तपाईँको स्क्रिनसट हेर्न छुनुहोस्।"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रिनसट क्याप्चर गर्न सकिएन।"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"स्क्रिनसटलाई बचत गर्न सकेन। भण्डारण उपयोगमा हुन सक्छ।"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB फाइल सार्ने विकल्पहरू"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"मिडिया प्लेयर(MTP)को रूपमा माउन्ट गर्नुहोस्"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"क्यामेराको रूपमा माउन्ट गर्नुहोस् (PTP)"</string>
@@ -169,7 +170,7 @@
     <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बन्द छ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बन्द छ"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेलुलर डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"तथ्याङ्क बन्द छ"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बन्द छ"</string>
     <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"तपाईंले सेट गर्नु भएको सीमा पुगेको हुनाले तपाईंको उपकरणले डेटा बंद गर्यो।\n\n यसलाई फिर्ता गर्दा आफ्नो वाहक बाट शुल्क लिन सक्छ।"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा खोल्नुहोस्"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"अतिथि"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+अतिथि"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"अतिथि बन्द"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"एक मिनेटको लागि"</item>
     <item quantity="other" msgid="6924190729213550991">"%d मिनेटको लागि"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ब्याट्री सेभर सेटिङ्हरू खुला गर्नुहोस्"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"निकास अतिथि"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले आफ्नो स्क्रीनमा प्रदर्शित हुने सबै खिच्न शुरू गर्नेछ।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"फेरि नदेखाउनुहोस्"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"अहिले सुरु गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 1122224..54e590f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om uw screenshot te bekijken."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan screenshot niet opslaan. Mogelijk is de opslag in gebruik."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Koppelen als camera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus verlaten"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Eén minuut"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minuten"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Instellingen voor Accubesparing openen"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Gastmodus verlaten"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op uw scherm."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Niet opnieuw weergeven"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Nu starten"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index bfa9b12..907f861 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Wykonano zrzut ekranu."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dotknij, aby wyświetlić zrzut ekranu."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nie udało się wykonać zrzutu ekranu."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Nie udało się zapisać zrzutu ekranu. Pamięć może być w użyciu."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB – opcje przesyłania plików"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Podłącz jako odtwarzacz multimedialny (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Podłącz jako aparat (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gość"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Dodaj gościa"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Zakończ tryb gościa"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Przez minutę"</item>
     <item quantity="other" msgid="6924190729213550991">"Przez %d min"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otwórz ustawienia oszczędzania baterii"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Zakończ tryb gościa"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Rozpocznij teraz"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 65d737a..b25c1a3 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de ecrã efetuada"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para ver a captura de ecrã"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter captura de ecrã."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Não foi possível guardar a captura de ecrã. O armazenamento poderá estar a ser utilizado."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opções de transm. de fich. USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Montar como leitor de multimédia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como câmara (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidado"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Sair de modo convidado"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durante um minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir as definições de poupança de bateria"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Sair de modo convidado"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"O(a) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vai começar a captar tudo o que é apresentado no ecrã."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar de novo"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Começar agora"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index a6df531..fc0d95a 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de tela obtida."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para visualizar a captura de tela."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter a captura de tela."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Não foi possível salvar a captura de tela. O armazenamento pode estar em uso."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opções transf. arq. por USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Conectar como media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como uma câmera (PTP)"</string>
@@ -168,18 +169,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Fechar painel"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Mais tempo"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Menos tempo"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Os dados 2G-3G foram desativados"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Os dados 4G foram desativados"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Os dados da rede celular foram desativados"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Os dados foram desativados"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O dispositivo desativou os dados porque o limite definido foi atingido.\n\nAtivá-los novamente poderá resultar em cobranças de sua operadora."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ativar dados"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
@@ -257,16 +252,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para cima."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para a esquerda."</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Sem interrupções, incluindo alarmes"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Sem interrupções"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Apenas interrupções prioritárias"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"Seu próximo alarme será às <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Seu próximo alarme será em <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"Você não ouvirá o alarme às <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
@@ -280,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ convidado"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Remover convidado"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Por 1 minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Por %d minutos"</item>
@@ -293,12 +297,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configurações de economia de bateria"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar agora"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 19dadc4..08c0691 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Captură de ecran realizată."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Atingeţi pentru a vedea captura de ecran."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Captura de ecran nu a putut fi realizată."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Captura de ecran nu a putut fi salvată. Este posibil să fie utilizată stocarea."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opţiuni pentru transferul de fişiere prin USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Montaţi ca player media (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montaţi drept cameră foto (PTP)"</string>
@@ -213,10 +214,10 @@
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio reţea"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nicio rețea salvată disponibilă"</string>
-    <string name="quick_settings_cast_title" msgid="1893629685050355115">"Trimiteți ecranul"</string>
-    <string name="quick_settings_casting" msgid="6601710681033353316">"Se trimite"</string>
+    <string name="quick_settings_cast_title" msgid="1893629685050355115">"Proiectați ecranul"</string>
+    <string name="quick_settings_casting" msgid="6601710681033353316">"Se proiectează"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispozitiv nedenumit"</string>
-    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pregătit pentru a trimite"</string>
+    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pregătit pentru proiecție"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Niciun dispozitiv disponibil"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Invitat"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Invitat"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Închideți invitatul"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Timp de un minut"</item>
     <item quantity="other" msgid="6924190729213550991">"Timp de %d (de) minute"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Deschideți setările pentru economisirea bateriei"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Închideți invitatul"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va începe să captureze tot ceea ce se afișează pe ecran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nu se mai afișează"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Începeți acum"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 8bbfd04..924c63e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сохранен"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Нажмите, чтобы просмотреть"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Не удалось сохранить скриншот."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Не удалось сохранить скриншот. Возможно, накопители заняты."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Параметры передачи через USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Подключить как мультимедийный проигрыватель (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Установить как камеру (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Гость"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Добавить гостя"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Выйти из гостевого режима"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 мин."</item>
     <item quantity="other" msgid="6924190729213550991">"%d мин."</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Открыть настройки режима энергосбережения"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Выйти из гостевого режима"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Приложение <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> получит доступ к изображению на экране устройства."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Больше не показывать"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Начать"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 7c5c702..929ab5d 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"තිර රුව ග්‍රහණය කරන ලදි."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"ඔබගේ තිර රුව බැලීමට ස්පර්ශ කරන්න."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"තිර රුව ග්‍රහණය කිරීමට නොහැකි විය."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"තිර රුව සුරැකීමට නොහැකි විය. ආචයනය භාවිතාවේ තිබෙනවා විය හැක."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ගොනු හුවමාරු විකල්ප"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"මධ්‍ය ධාවකයක් (MTP) ලෙස සවි කරන්න"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"කැමරාවක් (PTP) ලෙස සවි කරන්න"</string>
@@ -166,18 +167,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"පැනලය වහන්න"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"වේලාව වැඩියෙන්"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"වේලාව අඩුවෙන්"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G දත්ත නැත"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G දත්ත නැත"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"සෙලියුලර් දත්ත අක්‍රියයි"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"දත්ත අක්‍රියයි"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ඔබ සකසන ලද දත්ත සීමාවට එය ළඟාවී ඇති නිසා ඔබගේ උපාංගයේ දත්ත අක්‍රිය කර ඇත.\n\nඑය නැවත සක්‍රිය කිරීමෙන් ඔබගේ වාහකය ඇතැම් විට අය කර ගැනීමට හේතු වේ."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"දත්ත සක්‍රිය කරන්න"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS සඳහා සොයමින්"</string>
@@ -255,16 +250,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"සෙවීම"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා උඩට සර්පණය කරන්න."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා වමට සර්පණය කරන්න."</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"සීනු ඇතුළුව, අතුරු බිඳීම් නැත"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"අතුරු බිදුම් නැත"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"ප්‍රමුඛ අතුරු බිඳීම් පමණයි"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"ඔබගේ ඊළඟ සීනුව <xliff:g id="ALARM_TIME">%s</xliff:g> තිබේ"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ඔබගේ ඊළඟ සීනුව <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> වේ"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> හි තිබෙන ඔබගේ සීනුව ඔබට ඇසෙන්නේ නැත"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"හදිසිය අඩු දැනුම් දීම් පහත"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"විවෘත කිරීමට නැවත තට්ටු කරන්න"</string>
@@ -278,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"අමුත්තා"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ අමුත්තා"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"අමුත්තා පිටවීම"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"විනාඩි එකක් සඳහා"</item>
     <item quantity="other" msgid="6924190729213550991">"විනාඩි %d සඳහා"</item>
@@ -291,12 +295,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"බැටරි ඉතිරි කරන්නා සැකසීම් විවෘත කරන්න"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"ඔබගේ තීරයේ දර්ශනය වන සෑම දෙයම <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ලබාගැනීම ආරම්භ කරන ලදි."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"නැවත නොපෙන්වන්න"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"දැන් අරඹන්න"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 08b6221..53f2564 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímka obrazovky bola zaznamenaná."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímku obrazovky zobrazíte dotykom."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Snímku obrazovky sa nepodarilo zachytiť."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Snímku obrazovky sa nepodarilo uložiť. Ukladací priestor sa možno práve používa."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosu súborov USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pripojiť ako prehrávač médií (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Pripojiť ako fotoaparát (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Hosť"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Pridať hosťa"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončiť režim hosťa"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Na jednu minútu"</item>
     <item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvorte nastavenia šetriča batérie"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Ukončiť režim hosťa"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávať všetok obsah zobrazený na vašej obrazovke."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nabudúce nezobrazovať"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Spustiť"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index d73fff8..22914b0 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Posnetek zaslona je shranjen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Dotaknite se, če si želite ogledati posnetek zaslona."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Posnetka zaslona ni bilo mogoče shraniti."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Posnetka zaslona ni bilo mogoče shraniti. Shramba je morda v uporabi."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosa datotek prek USB-ja"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Vpni kot predvajalnik (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Vpni kot fotoaparat (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Dodajanje gosta"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Izhod iz načina za goste"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Za %d min"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Odpri nastavitve varčevanja z energijo akumulatorja"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Izhod iz načina za goste"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bo začela zajemati vse, kar je prikazano na zaslonu."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Tega ne prikaži več"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Začni zdaj"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f08af24..fd66ff3 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Снимак екрана је направљен."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Додирните да бисте видели снимак екрана."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Није могуће направити снимак екрана."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Није могуће сачувати снимак екрана. Могуће је да је меморија у употреби."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Опције USB преноса датотека"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Прикључи као медија плејер (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Прикључи као камеру (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Гост"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Изађи из режима госта"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Један минут"</item>
     <item quantity="other" msgid="6924190729213550991">"%d мин"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отворите подешавања Штедње батерије"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Изађи из режима госта"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ће почети да снима све што се приказује на екрану."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Не приказуј поново"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Започни одмах"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4e3caa1..69c47e4 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Skärmdumpen har tagits."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Tryck här om du vill visa skärmdumpen."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Det gick inte att ta någon skärmdump."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Det gick inte att spara skärmdumpen. Extern lagring kanske används."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Överföringsalternativ"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Montera som mediaspelare (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Montera som kamera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Gäst"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Lägg till gäst"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Avsluta gäst"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"I en minut"</item>
     <item quantity="other" msgid="6924190729213550991">"I %d minuter"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Öppna inställningarna för batterisparläget"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Avsluta gäst"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar en bild av allt som visas på skärmen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Visa inte igen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Starta nu"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 9c3e05a..9aa90496 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -71,7 +71,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Picha ya skrini imenaswa."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Gusa ili kuona picha yako ya skrini."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Haikuweza kunasa picha ya skrini"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Haikuweza kuhifadhi picha ya skrini. Huenda hifadhi inatumika."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Machaguo ya uhamisho wa faili la USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Angika kama kichezeshi cha midia (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Angika kama kamera (PTP)"</string>
@@ -168,7 +169,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data ya 4G imezimwa"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data ya simu ya mkononi imezimwa"</string>
     <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data imezimwa"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Kifaa chako kilizima data kwa sababu kilifikia kikomo ulichoweka.\n\nKukiwasha tena kunaweza kupelekea utozwe na mtoa huduma wako."</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Kifaa chako kilizima data kwa sababu kilifikia kikomo ulichoweka.\n\nKuwasha data tena kunaweza kusababisha matozo kutoka kwa mtoa huduma wako."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Washa matumizi ya data"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
@@ -247,7 +248,7 @@
     <string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Sogeza juu kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Sogeza kushoto kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Hakuna katizo, ikiwa ni pamoja na kengele"</string>
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"Hakuna kukatizwa, hata kutoka kwenye kengele"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Hakuna katizo"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Katizo za kipaumbele pekee"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Kengele yako inayofuata itakuwa saa <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -266,6 +267,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji ( <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hadi ijae)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Aliyealikwa"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Aliyealikwa"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Ondoa aliyealikwa"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Kwa dakika moja"</item>
     <item quantity="other" msgid="6924190729213550991">"Kwa dakika %d"</item>
@@ -279,7 +293,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Fungua mipangilio ya hali inayookoa betri"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Ondoa aliyealikwa"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> itaanza kupiga picha kila kitu kinachoonyeshwa kwenye skrini yako."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Usionyeshe tena"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Anza sasa"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index a5e3924..953a3ab 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -62,4 +62,22 @@
          keyguard_clock_height_fraction_* for the difference between min and max.-->
     <dimen name="keyguard_clock_notifications_margin_min">44dp</dimen>
     <dimen name="keyguard_clock_notifications_margin_max">44dp</dimen>
+
+    <!-- Height of the status bar header bar when on Keyguard -->
+    <dimen name="status_bar_header_height_keyguard">60dp</dimen>
+
+    <!-- The width of user avatar when on Keyguard -->
+    <dimen name="multi_user_switch_width_keyguard">48dp</dimen>
+
+    <!-- The width of user avatar when on Keyguard -->
+    <dimen name="multi_user_avatar_keyguard_size">30dp</dimen>
+
+    <!-- end margin for multi user switch in collapsed quick settings -->
+    <dimen name="multi_user_switch_keyguard_margin">6dp</dimen>
+
+    <!-- Margin on the left side of the carrier text on Keyguard -->
+    <dimen name="keyguard_carrier_text_margin">24dp</dimen>
+
+    <!-- end margin for system icons if multi user switch is hidden -->
+    <dimen name="system_icons_switcher_hidden_expanded_margin">20dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index ab76f71..e9b0394 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"உங்கள் ஸ்க்ரீன் ஷாட்டைப் பார்க்க தொடவும்."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ஸ்க்ரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"ஸ்கீர்ன் ஷாட்டைச் சேமிக்க முடியவில்லை. சேமிப்பிடம் பயன்பாட்டில் இருக்கலாம்."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"(MTP) மீடியா பிளேயராக ஏற்று"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"(PTP) கேமராவாக ஏற்று"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"அழைக்கப்பட்டவர்"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ அழைக்கப்பட்டவர்"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"விருந்தினரிலிருந்து வெளியேறு"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ஒரு நிமிடம்"</item>
     <item quantity="other" msgid="6924190729213550991">"%d நிமிடங்கள்"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"பேட்டரி சேமிப்பான் அமைப்புகளைத் திற"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"விருந்தினரிலிருந்து வெளியேறு"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"திரையில் காட்டப்படும் அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> படமெடுக்கும்."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"மீண்டும் காட்டாதே"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"இப்போது தொடங்கு"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index cbab00f..687a110 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"స్క్రీన్‌షాట్ క్యాప్చర్ చేయబడింది."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"మీ స్క్రీన్‌షాట్‌ను వీక్షించడానికి తాకండి."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"స్క్రీన్‌షాట్‌ను క్యాప్చర్ చేయడం సాధ్యపడలేదు."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"స్క్రీన్‌షాట్‌ను సేవ్ చేయడం సాధ్యపడలేదు. నిల్వ ఉపయోగంలో ఉండవచ్చు."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB ఫైల్ బదిలీ ఎంపికలు"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"మీడియా ప్లేయర్‌గా (MTP) మౌంట్ చేయి"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"కెమెరాగా (PTP) మౌంట్ చేయి"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"అతిథి"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ అతిథి"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"అతిథి మోడ్ నుండి నిష్క్రమించండి"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ఒక నిమిషానికి"</item>
     <item quantity="other" msgid="6924190729213550991">"%d నిమిషాలకి"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"బ్యాటరీ సేవర్ సెట్టింగ్‌లను తెరువు"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్‌లు దాచబడ్డాయి"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"అతిథి మోడ్ నుండి నిష్క్రమించండి"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> మీ స్క్రీన్‌పై కనిపించే ప్రతిదాన్ని క్యాప్చర్ చేయడం ప్రారంభిస్తుంది."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"మళ్లీ చూపవద్దు"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ఇప్పుడే ప్రారంభించు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 215d3e1..4f2cb6f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"จับภาพหน้าจอแล้ว"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"แตะเพื่อดูภาพหน้าจอของคุณ"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ไม่สามารถจับภาพหน้าจอ"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"ไม่สามารถบันทึกภาพหน้าจอ ที่จัดเก็บข้อมูลอาจมีการใช้งานอยู่"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"ตัวเลือกการถ่ายโอนไฟล์ USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"ต่อเชื่อมเป็นโปรแกรมเล่นสื่อ (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"ต่อเชื่อมเป็นกล้องถ่ายรูป (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"ผู้เข้าร่วม"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ ผู้เข้าร่วม"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"ออกจากโหมดผู้เยี่ยมชม"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 นาที"</item>
     <item quantity="other" msgid="6924190729213550991">"%d นาที"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"เปิดการตั้งค่าโหมดประหยัดแบตเตอรี่"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาที่ซ่อน"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"ออกจากโหมดผู้เยี่ยมชม"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะเริ่มจับภาพทุกอย่างที่แสดงบนหน้าจอ"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ไม่ต้องแสดงข้อความนี้อีก"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"เริ่มเลย"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9387e9e..4a6007c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Nakuha ang screenshot."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Pindutin upang tingnan ang iyong screenshot."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Hindi makuha ang screenshot."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Hindi ma-save ang screenshot. Maaaring ginagamit ang storage."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Opsyon paglipat ng USB file"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"I-mount bilang isang media player (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"I-mount bilang camera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Bisita"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Bisita"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Lumabas bilang guest"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Sa loob ng isang minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Sa loob ng %d (na) minuto"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buksan ang mga setting ng tagatipid ng baterya"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Lumabas bilang guest"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Sisimulan ng i-capture ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang lahat ng ipinapakita sa iyong screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Huwag ipakitang muli"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Magsimula ngayon"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c00ec90..7938f3d 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran görüntüsü alındı."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Ekran görüntünüzü izlemek için dokunun."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran görüntüsü alınamadı."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Ekran görüntüsü kaydedilemedi. Depolama birimi kullanımda olabilir."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB dosya aktarım seçenekleri"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Medya oynatıcı olarak ekle (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera olarak ekle (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Misafir"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Misafir"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Misafir oturumundan çık"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Bir dakika süreyle"</item>
     <item quantity="other" msgid="6924190729213550991">"%d dakika süreyle"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Pil tasarrufu ayarlarını aç"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"%%<xliff:g id="LEVEL">%d</xliff:g>"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Misafir oturumundan çık"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ekranınızda görüntülenen her şeyi kaydetmeye başlayacak."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Bir daha gösterme"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Şimdi başla"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 49abb62..c2259f8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Знімок екрана зроблено."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Торкніться, щоб переглянути знімок екрана."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Не вдалося зробити знімок екрана."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Не вдалося зберегти знімок екрана. Можливо, пам’ять використовується."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Парам.передав.файлів через USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Підключити як медіапрогравач (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Підключити як камеру (PTP)"</string>
@@ -170,7 +171,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Дані 4G вимкнено"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобільні дані вимкнено"</string>
     <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дані вимкнено"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Пристрій вимкнув передавання даних, оскільки на ньому досягнуто встановленого вами ліміту.\n\nЯкщо передавання даних знову ввімкнути, оператор може стягувати з вас плату за це."</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Пристрій вимкнув передавання даних, оскільки перевищено встановлений вами ліміт.\n\nЯкщо передавання даних знову ввімкнути, оператор може стягувати додаткову плату."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Увімкнути дані"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Гість"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"Додати гостя"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Вийти з режиму гостя"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Протягом хвилини"</item>
     <item quantity="other" msgid="6924190729213550991">"Протягом %d хв"</item>
@@ -281,8 +295,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Відкрийте налаштування режиму заощадження заряду акумулятора"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Вийти з гостьового режиму"</string>
-    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> почне збирати всі дані, які відображаються на вашому екрані."</string>
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримає доступ до всіх даних, які відображаються на вашому екрані."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Більше не показувати"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Почати зараз"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index aa15d23..e2e1704 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"اسکرین شاٹ کیپچر کیا گیا۔"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"اپنے اسکرین شاٹ دیکھنے کیلئے چھوئیں۔"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"اسکرین شاٹ کیپچر نہیں کر سکے۔"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"اسکرین شاٹ محفوظ نہیں کر سکے۔ ممکن ہے اسٹوریج کا استعمال ہو رہا ہے۔"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"‏USB فائل منتقل کرنیکے اختیارات"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏ایک میڈیا پلیئر (MTP) کے بطور ماؤنٹ کریں"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"‏ایک کیمرہ (PTP) کے بطور ماؤنٹ کریں"</string>
@@ -170,7 +171,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"‏4G ڈیٹا آف ہے"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"سیلولر ڈیٹا آف ہے"</string>
     <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"آپ کے آلہ نے ڈیٹا کو آف کر دیا کیونکہ یہ آپ کے متعینہ حد کو پہنچ گیا ہے۔\n\nاسے دوبارہ آن کرنے سے آپ کے کیریئر کی جانب سے چارجز عائد ہو سکتے ہیں۔"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"آپ کے آلہ نے ڈیٹا کو آف کر دیا کیونکہ یہ آپ کی متعینہ حد کو پہنچ گیا۔\n\nاسے دوبارہ آن کرنے سے آپ کے کیریئر کی جانب سے چارجز عائد ہو سکتے ہیں۔"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ڈیٹا آن کریں"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi مربوط ہے"</string>
@@ -252,9 +253,9 @@
     <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"الارمز کے بشمول، کوئی مداخلتیں نہیں ہیں"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"کوئی مداخلتیں نہیں ہیں"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"صرف ترجیحی مداخلتیں"</string>
-    <string name="zen_alarm_information_time" msgid="5235772206174372272">"آپ کا اگلا الارم بوقت <xliff:g id="ALARM_TIME">%s</xliff:g> ہے"</string>
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"آپ کا اگلا الارم <xliff:g id="ALARM_TIME">%s</xliff:g> بجے ہے"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"آپ کا اگلا الارم <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> ہے"</string>
-    <string name="zen_alarm_warning" msgid="6873910860111498041">"آپ کو بوقت <xliff:g id="ALARM_TIME">%s</xliff:g> اپنا الارم سنائی نہیں دیگا"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"آپ کو <xliff:g id="ALARM_TIME">%s</xliff:g> بجے اپنا الارم سنائی نہیں دیگا"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"‎+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>‎"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"کم اہم اطلاعات ذیل میں ہیں"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"کھولنے کیلئے دوبارہ تھپتھپائیں"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"مہمان"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ مہمان"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"مہمان وضع سے باہر نکلیں"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ایک منٹ کیلئے"</item>
     <item quantity="other" msgid="6924190729213550991">"‏%d منٹ کیلئے"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"بیٹری سیور کی ترتیبات کھولیں"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"‎<xliff:g id="LEVEL">%d</xliff:g>%%‎"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"مہمان سے باہر نکلیں"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> آپ کی اسکرین پر ڈسپلے ہونے والی ہر چیز کو کیپچر کرنا شروع کر دیگی۔"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"دوبارہ نہ دکھائیں"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ابھی شروع کریں"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 7a551d3..cdc55e6 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran surati olindi."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Ekraningiz suratini ko‘rish uchun bosing."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran surati olinmadi."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Ekran surati saqlanmadi. Xotiradan foydalanilayotgan bo‘lishi mumkin."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB fayl ko‘chirish moslamalari"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer sifatida ulash (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera sifatida ulash (PTP)"</string>
@@ -166,18 +167,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Panelni yopish"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Vaqtni ko‘paytirish"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Vaqtni kamaytirish"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobil internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Internet o‘chirib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Siz o‘rnatgan chegaraga yetib kelgani tufayli qurilmangizda internet o‘chirib qo‘yildi.\n\nUni qayta yoqishingiz mumkin, biroq buning uchun aloqa operatoringiz qo‘shimcha haq olishi mumkin."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Internetni yoqish"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS qidirilmoqda"</string>
@@ -255,16 +250,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"Izlash"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun yuqoriga suring."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun chapga suring."</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"“Bezovta qilmaslik” rejimi (uyg‘otkich ovozi o‘chirilgan)"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Tanaffuslarsiz"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Faqat ustuvor tanaffuslar"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"Keyingi uyg‘otkich: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Keyingi uyg‘otkich: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"Keyingi uyg‘otkich: <xliff:g id="ALARM_TIME">%s</xliff:g>. Ovoz eshitilmaydi."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Kam ahamiyatli bildirishnomalarni pastda ko‘rsatish"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ochish uchun yana bosing"</string>
@@ -278,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Mehmon"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Mehmon"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Mehmon rejimidan chiqish"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 daqiqa"</item>
     <item quantity="other" msgid="6924190729213550991">"%d daqiqa"</item>
@@ -291,12 +295,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Quvvat tejash sozlamalarini ochish"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi qurilma ekranidagi har qanday tasvirni ko‘rishni boshlaydi."</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Boshqa ko‘rsatilmasin"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"Boshlash"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index bf32e6c..c39ec02 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Đã chụp ảnh màn hình."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Chạm để xem ảnh chụp màn hình của bạn."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Không thể chụp ảnh màn hình."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Không thể lưu ảnh chụp màn hình. Bộ lưu trữ có thể đang được sử dụng."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Tùy chọn truyền tệp USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Gắn như một trình phát đa phương tiện (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Gắn như một máy ảnh (PTP)"</string>
@@ -170,7 +171,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dữ liệu 4G bị tắt"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Dữ liệu di động bị tắt"</string>
     <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dữ liệu bị tắt"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Thiết bị của bạn bị tắt dữ liệu do đã đạt đến giới hạn bạn đã đặt.\n\nViệc bật lại dữ liệu có thể dẫn tới các khoản phí từ nhà cung cấp dịch vụ của bạn."</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Thiết bị của bạn đã tắt dữ liệu do đã đạt đến giới hạn bạn đã đặt.\n\nViệc bật lại dữ liệu có thể dẫn tới các khoản phí từ nhà cung cấp dịch vụ của bạn."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Bật dữ liệu"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Khách"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Khách"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Thoát chế độ khách"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Trong một phút"</item>
     <item quantity="other" msgid="6924190729213550991">"Trong %d phút"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Mở cài đặt trình tiết kiệm pin"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Thoát chế độ khách"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ bắt đầu chụp mọi thứ hiển thị trên màn hình."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Không hiển thị lại"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Bắt đầu ngay"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 92ee5a2..111e0a2 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"已抓取屏幕截图。"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"触摸可查看您的屏幕截图。"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"无法抓取屏幕截图。"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"无法保存屏幕截图。存储设备可能正在使用中。"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 文件传输选项"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"作为媒体播放器 (MTP) 装载"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"作为摄像头 (PTP) 装载"</string>
@@ -138,7 +139,7 @@
     <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"漫游中"</string>
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"EDGE"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"WLAN"</string>
-    <string name="accessibility_no_sim" msgid="8274017118472455155">"无 SIM 卡。"</string>
+    <string name="accessibility_no_sim" msgid="8274017118472455155">"无SIM卡。"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"蓝牙网络共享。"</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"飞行模式。"</string>
     <!-- String.format failed for translation -->
@@ -168,18 +169,12 @@
     <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"关闭面板"</string>
     <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"更长时间"</string>
     <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"更短时间"</string>
-    <!-- no translation found for data_usage_disabled_dialog_3g_title (2626865386971800302) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_4g_title (4629078114195977196) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_mobile_title (5793456071535876132) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_title (8723412000355709802) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog (6468718338038876604) -->
-    <skip />
-    <!-- no translation found for data_usage_disabled_dialog_enable (5538068036107372895) -->
-    <skip />
+    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G数据网络已关闭"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G数据网络已关闭"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"移动数据网络已关闭"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"数据网络已关闭"</string>
+    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"由于数据流量已达到您所设置的上限,因此您的设备已关闭数据网络。\n\n如果重新开启数据网络,那么您的运营商可能会向您收取相应费用。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"开启数据网络"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN 已连接"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索 GPS"</string>
@@ -257,16 +252,12 @@
     <string name="description_target_search" msgid="3091587249776033139">"搜索"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"向左滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <!-- no translation found for zen_no_interruptions_with_warning (2522931836819051293) -->
-    <skip />
+    <string name="zen_no_interruptions_with_warning" msgid="2522931836819051293">"禁止打扰(包括闹钟)"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"禁止打扰"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"仅限优先打扰内容"</string>
-    <!-- no translation found for zen_alarm_information_time (5235772206174372272) -->
-    <skip />
-    <!-- no translation found for zen_alarm_information_day_time (8422733576255047893) -->
-    <skip />
-    <!-- no translation found for zen_alarm_warning (6873910860111498041) -->
-    <skip />
+    <string name="zen_alarm_information_time" msgid="5235772206174372272">"下次闹钟响铃时间:<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"下次闹钟响铃时间:<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
+    <string name="zen_alarm_warning" msgid="6873910860111498041">"您在<xliff:g id="ALARM_TIME">%s</xliff:g>将不会听到闹钟响铃"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"不太紧急的通知会显示在下方"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次点按即可打开"</string>
@@ -280,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"访客"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"添加新访客"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"退出访客模式"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1分钟"</item>
     <item quantity="other" msgid="6924190729213550991">"%d分钟"</item>
@@ -293,12 +297,7 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"打开节电助手设置"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string>
-    <!-- no translation found for guest_exit_guest (1619100760451149682) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
-    <skip />
-    <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
-    <skip />
-    <!-- no translation found for media_projection_action_text (8470872969457985954) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>将开始截取您的屏幕上显示的所有内容。"</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"不再显示"</string>
+    <string name="media_projection_action_text" msgid="8470872969457985954">"立即开始"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 2e3878d..298aac1 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"已擷取螢幕畫面。"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"輕觸即可查看螢幕擷取畫面。"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"無法擷取螢幕畫面。"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"無法儲存螢幕擷取畫面,儲存裝置可能正在使用。"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
     <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟省電設定"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"不用再顯示"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"立即開始"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 840778b..d766aca 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"已拍攝螢幕擷取畫面。"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"輕觸即可查看螢幕擷取畫面。"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"無法拍攝螢幕擷取畫面。"</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"無法儲存螢幕擷取畫面,儲存空間可能正在使用中。"</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string>
@@ -270,6 +271,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
     <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
@@ -283,7 +297,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟節約耗電量設定"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"結束訪客模式"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"不要再顯示"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"立即開始"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 38e4d8f..7e49f6e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -73,7 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Umfanekiso weskrini uqoshiwe"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Thinta ukubona imifanekiso yakho yeskrini"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Yehlulekile ukulondoloza umfanekiso weskrini."</string>
-    <string name="screenshot_failed_text" msgid="8134011269572415402">"Ayikwazanga ukulondoloza isithombe-skrini. Isitoreji sangaphandle kungenzeka kuyasetshenziswa."</string>
+    <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
+    <skip />
     <string name="usb_preference_title" msgid="6551050377388882787">"Okukhethwa kokudluliswa kwefayela ye-USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Lengisa njengesidlali semediya (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Lengisa ikhamera (PTP)"</string>
@@ -268,6 +269,19 @@
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Isihambeli"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Isihambeli"</string>
+    <string name="guest_exit_guest" msgid="1619100760451149682">"Phuma kusivakashi"</string>
+    <!-- no translation found for guest_exit_guest_dialog_title (7587460301980067285) -->
+    <skip />
+    <!-- no translation found for guest_exit_guest_dialog_message (10255285459589280) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_message (5369763062345463297) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_wipe (9154291314115781448) -->
+    <skip />
+    <!-- no translation found for guest_wipe_session_dontwipe (850084868661344050) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Iminithi elilodwa"</item>
     <item quantity="other" msgid="6924190729213550991">"Amaminithi angu-%d"</item>
@@ -281,7 +295,6 @@
     <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Vula izilungiselelo zesilondolozi sebhethri"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string>
-    <string name="guest_exit_guest" msgid="1619100760451149682">"Phuma kusivakashi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> izoqala ukuthwebula yonke into eboniswa kusikrini sakho."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ungabonisi futhi"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Qala manje"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e9fe09e..a718f4f 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -62,7 +62,7 @@
     <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
     <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color>
     <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
-    <color name="recents_task_bar_dark_dismiss_color">#cc000000</color>
+    <color name="recents_task_bar_dark_dismiss_color">#99000000</color>
     <!-- The recents task bar highlight color. -->
     <color name="recents_task_bar_highlight_color">#28ffffff</color>
     <!-- The lock to task button background color. -->
@@ -94,4 +94,10 @@
     <color name="current_user_border_color">@color/system_accent_color</color>
 
     <color name="segmented_button_text_inactive">#99afbdc4</color><!-- 60% -->
+
+    <!-- The "inside" of a notification, reached via longpress -->
+    <color name="notification_guts_bg_color">#ff424242</color><!-- grey 800 -->
+    <color name="notification_guts_title_color">#FFFFFFFF</color>
+    <color name="notification_guts_text_color">#99FFFFFF</color>
+    <color name="notification_guts_btn_color">#FFFFFFFF</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8b11ef1..230f4af 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -159,8 +159,14 @@
     <!-- Set to true to enable the user switcher on the keyguard. -->
     <bool name="config_keyguardUserSwitcher">false</bool>
 
+    <!-- Doze: does this device support STATE_DOZE and STATE_DOZE_SUSPEND?  -->
+    <bool name="doze_display_state_supported">false</bool>
+
     <!-- Doze: should the significant motion sensor be used as a tease signal? -->
-    <bool name="doze_tease_on_significant_motion">true</bool>
+    <bool name="doze_tease_on_significant_motion">false</bool>
+
+    <!-- Doze: maximum brightness to use when teasing -->
+    <integer name="doze_tease_brightness">80</integer>
 
     <!-- Volume: time to delay dismissing the volume panel after a click is performed -->
     <integer name="volume_panel_dismiss_delay">200</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bb18120..bd10623 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -213,6 +213,9 @@
     <!-- The height of the lock-to-app button. -->
     <dimen name="recents_task_view_lock_to_app_button_height">48dp</dimen>
 
+    <!-- The amount to offset when animating into an affiliate group. -->
+    <dimen name="recents_task_view_affiliate_group_enter_offset">64dp</dimen>
+
     <!-- The height of a task view bar. -->
     <dimen name="recents_task_bar_height">56dp</dimen>
 
@@ -292,6 +295,15 @@
     <!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
     <dimen name="keyguard_min_swipe_amount">75dp</dimen>
 
+    <!-- The minimum background radius when swiping to a side for the camera / phone affordances. -->
+    <dimen name="keyguard_affordance_min_background_radius">30dp</dimen>
+
+    <!-- The grow amount for the camera and phone circles when hinting -->
+    <dimen name="hint_grow_amount_sideways">60dp</dimen>
+
+    <!-- The chevron padding to the circle when hinting -->
+    <dimen name="hint_chevron_circle_padding">16dp</dimen>
+
     <!-- Volume panel dialog y offset -->
     <dimen name="volume_panel_top">0dp</dimen>
 
@@ -314,9 +326,6 @@
     <!-- Move distance for the unlock hint animation on the lockscreen -->
     <dimen name="hint_move_distance">75dp</dimen>
 
-    <!-- Move distance for the other hint animations on the lockscreen (phone, camera)-->
-    <dimen name="hint_move_distance_sideways">60dp</dimen>
-
     <!-- The width of the region on the left/right edge of the screen for performing the camera/
          phone hints. -->
     <dimen name="edge_tap_area_width">48dp</dimen>
@@ -344,15 +353,24 @@
     <!-- The padding bottom of the clock group when QS is expanded. -->
     <dimen name="clock_expanded_bottom_margin">20dp</dimen>
 
+    <!-- The padding bottom of the clock group when QS is collapsed. -->
+    <dimen name="clock_collapsed_bottom_margin">10dp</dimen>
+
     <!-- The width of the multi user switch on keyguard and collapsed QS header. -->
     <dimen name="multi_user_switch_width_collapsed">34dp</dimen>
 
     <!-- The width of the multi user switch in expanded QS header. -->
     <dimen name="multi_user_switch_width_expanded">48dp</dimen>
 
+    <!-- The width of user avatar when on Keyguard -->
+    <dimen name="multi_user_switch_width_keyguard">34dp</dimen>
+
     <!-- The width of user avatar when collapsed -->
     <dimen name="multi_user_avatar_collapsed_size">22dp</dimen>
 
+    <!-- The width of user avatar when on Keyguard -->
+    <dimen name="multi_user_avatar_keyguard_size">22dp</dimen>
+
     <!-- The font size of the time when collapsed in QS -->
     <dimen name="qs_time_collapsed_size">14sp</dimen>
 
@@ -362,7 +380,19 @@
     <!-- Battery level padding end when in expanded QS (but not on Keyguard) -->
     <dimen name="battery_level_padding_end">4dp</dimen>
 
+    <!-- The top padding of the clear all button -->
+    <dimen name="clear_all_padding_top">4dp</dimen>
+
     <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
          quick settings header -->
     <dimen name="max_avatar_size">48dp</dimen>
+
+    <!-- Margin on the left side of the carrier text on Keyguard -->
+    <dimen name="keyguard_carrier_text_margin">16dp</dimen>
+
+    <!-- Margin on the left side of the battery % in the header. -->
+    <dimen name="header_battery_margin_expanded">8dp</dimen>
+
+    <!-- Margin on the left side of the battery % when on Keyguard. -->
+    <dimen name="header_battery_margin_keyguard">6dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 416cd54..085d2f9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -380,8 +380,12 @@
     <!-- Content description of the ringer silent icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_ringer_silent">Ringer silent.</string>
 
+    <!-- Content description to tell the user that this button will remove an application from recents -->
+    <string name="accessibility_recents_item_will_be_dismissed">Dismiss <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Content description to tell the user an application has been removed from recents -->
     <string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
+    <!-- Content description to tell the user an application has been launched from recents -->
+    <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Content description to tell the user a notification has been removed from the notification shade -->
     <string name="accessibility_notification_dismissed">Notification dismissed.</string>
 
@@ -732,6 +736,12 @@
     <!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] -->
     <string name="media_projection_remember_text">Don\'t show again</string>
 
+    <!-- The text to clear all notifications. [CHAR LIMIT=60] -->
+    <string name="clear_all_notifications_text">Clear all</string>
+
     <!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
     <string name="media_projection_action_text">Start now</string>
+
+    <!-- Text which is shown in the notification shade when there are no notifications. [CHAR LIMIT=30] -->
+    <string name="empty_shade_text">No notifications</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0b8f876..61e6121 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -249,6 +249,11 @@
         <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>
+    </style>
+
     <style name="NotificationsQuickSettings">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
@@ -275,7 +280,4 @@
         <item name="android:textStyle">italic</item>
         <item name="android:textColor">#60000000</item>
     </style>
-
-    <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
-    </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 5e48258..b9ffdbb 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -402,6 +402,11 @@
         }
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     private boolean mDemoMode;
     private BatteryTracker mDemoTracker = new BatteryTracker();
 
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index bbda536..a26c534 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -29,11 +29,13 @@
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
 
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 
 public class ExpandHelper implements Gefingerpoken {
@@ -49,7 +51,7 @@
     private static final String TAG = "ExpandHelper";
     protected static final boolean DEBUG = false;
     protected static final boolean DEBUG_SCALE = false;
-    private static final long EXPAND_DURATION = 250;
+    private static final float EXPAND_DURATION = 0.3f;
 
     // Set to false to disable focus-based gestures (spread-finger vertical pull).
     private static final boolean USE_DRAG = true;
@@ -112,6 +114,8 @@
     private int mGravity;
 
     private ScrollAdapter mScrollAdapter;
+    private FlingAnimationUtils mFlingAnimationUtils;
+    private VelocityTracker mVelocityTracker;
 
     private OnScaleGestureListener mScaleGestureListener
             = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@@ -171,7 +175,6 @@
         mScaler = new ViewScaler();
         mGravity = Gravity.TOP;
         mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
-        mScaleAnimation.setDuration(EXPAND_DURATION);
         mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
         mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
 
@@ -179,6 +182,7 @@
         mTouchSlop = configuration.getScaledTouchSlop();
 
         mSGD = new ScaleGestureDetector(context, mScaleGestureListener);
+        mFlingAnimationUtils = new FlingAnimationUtils(context, EXPAND_DURATION);
     }
 
     private void updateExpansion() {
@@ -260,6 +264,7 @@
         if (!isEnabled()) {
             return false;
         }
+        trackVelocity(ev);
         final int action = ev.getAction();
         if (DEBUG_SCALE) Log.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) +
                          " expanding=" + mExpanding +
@@ -279,6 +284,7 @@
 
         if (mExpanding) {
             mLastMotionY = ev.getRawY();
+            maybeRecycleVelocityTracker(ev);
             return true;
         } else {
             if ((action == MotionEvent.ACTION_MOVE) && 0 != (mExpansionStyle & BLINDS)) {
@@ -323,15 +329,52 @@
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 if (DEBUG) Log.d(TAG, "up/cancel");
-                finishExpanding(false);
+                finishExpanding(false, getCurrentVelocity());
                 clearView();
                 break;
             }
             mLastMotionY = ev.getRawY();
+            maybeRecycleVelocityTracker(ev);
             return mExpanding;
         }
     }
 
+    private void trackVelocity(MotionEvent event) {
+        int action = event.getActionMasked();
+        switch(action) {
+            case MotionEvent.ACTION_DOWN:
+                if (mVelocityTracker == null) {
+                    mVelocityTracker = VelocityTracker.obtain();
+                } else {
+                    mVelocityTracker.clear();
+                }
+                mVelocityTracker.addMovement(event);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                mVelocityTracker.addMovement(event);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void maybeRecycleVelocityTracker(MotionEvent event) {
+        if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
+                || event.getActionMasked() == MotionEvent.ACTION_UP) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    private float getCurrentVelocity() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.computeCurrentVelocity(1000);
+            return mVelocityTracker.getYVelocity();
+        } else {
+            return 0f;
+        }
+    }
+
     public void setEnabled(boolean enable) {
         mEnabled = enable;
     }
@@ -349,6 +392,7 @@
         if (!isEnabled()) {
             return false;
         }
+        trackVelocity(ev);
         final int action = ev.getActionMasked();
         if (DEBUG_SCALE) Log.d(TAG, "touch: act=" + MotionEvent.actionToString(action) +
                 " expanding=" + mExpanding +
@@ -438,11 +482,12 @@
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
                 if (DEBUG) Log.d(TAG, "up/cancel");
-                finishExpanding(false);
+                finishExpanding(false, getCurrentVelocity());
                 clearView();
                 break;
         }
         mLastMotionY = ev.getRawY();
+        maybeRecycleVelocityTracker(ev);
         return mResizedView != null;
     }
 
@@ -476,7 +521,7 @@
         return true;
     }
 
-    private void finishExpanding(boolean force) {
+    private void finishExpanding(boolean force, float velocity) {
         if (!mExpanding) return;
 
         if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mResizedView);
@@ -506,6 +551,7 @@
                     mScaleAnimation.removeListener(this);
                 }
             });
+            mFlingAnimationUtils.apply(mScaleAnimation, currentHeight, targetHeight, velocity);
             mScaleAnimation.start();
         } else {
             mCallback.setUserLockedChild(mResizedView, false);
@@ -529,7 +575,7 @@
      * Use this to abort any pending expansions in progress.
      */
     public void cancel() {
-        finishExpanding(true);
+        finishExpanding(true, 0f /* velocity */);
         clearView();
 
         // reset the gesture detector
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d153d09..6c30c89 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
 import android.graphics.RectF;
 import android.os.Handler;
 import android.util.Log;
@@ -29,6 +30,8 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 
 public class SwipeHelper implements Gefingerpoken {
@@ -44,6 +47,7 @@
     public static final int Y = 1;
 
     private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+    private final Interpolator mFastOutLinearInInterpolator;
 
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
     private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
@@ -72,23 +76,26 @@
     private float mDensityScale;
 
     private boolean mLongPressSent;
-    private View.OnLongClickListener mLongPressListener;
+    private LongPressListener mLongPressListener;
     private Runnable mWatchLongPress;
     private long mLongPressTimeout;
 
-    public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
-            float pagingTouchSlop) {
+    final private int[] mTmpPos = new int[2];
+
+    public SwipeHelper(int swipeDirection, Callback callback, Context context) {
         mCallback = callback;
         mHandler = new Handler();
         mSwipeDirection = swipeDirection;
         mVelocityTracker = VelocityTracker.obtain();
-        mDensityScale = densityScale;
-        mPagingTouchSlop = pagingTouchSlop;
+        mDensityScale =  context.getResources().getDisplayMetrics().density;
+        mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
 
         mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                android.R.interpolator.fast_out_linear_in);
     }
 
-    public void setLongPressListener(View.OnLongClickListener listener) {
+    public void setLongPressListener(LongPressListener listener) {
         mLongPressListener = listener;
     }
 
@@ -210,7 +217,7 @@
         }
     }
 
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
+    public boolean onInterceptTouchEvent(final MotionEvent ev) {
         final int action = ev.getAction();
 
         switch (action) {
@@ -232,8 +239,12 @@
                                 public void run() {
                                     if (mCurrView != null && !mLongPressSent) {
                                         mLongPressSent = true;
-                                        mCurrView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
-                                        mLongPressListener.onLongClick(mCurrView);
+                                        mCurrView.sendAccessibilityEvent(
+                                                AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+                                        mCurrView.getLocationOnScreen(mTmpPos);
+                                        final int x = (int) ev.getRawX() - mTmpPos[0];
+                                        final int y = (int) ev.getRawY() - mTmpPos[1];
+                                        mLongPressListener.onLongPress(mCurrView, x, y);
                                     }
                                 }
                             };
@@ -262,14 +273,16 @@
 
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
+                final boolean captured = (mDragging || mLongPressSent);
                 mDragging = false;
                 mCurrView = null;
                 mCurrAnimView = null;
                 mLongPressSent = false;
                 removeLongPressCallback();
+                if (captured) return true;
                 break;
         }
-        return mDragging;
+        return mDragging || mLongPressSent;
     }
 
     /**
@@ -277,6 +290,19 @@
      * @param velocity The desired pixels/second speed at which the view should move
      */
     public void dismissChild(final View view, float velocity) {
+        dismissChild(view, velocity, null, 0, false, 0);
+    }
+
+    /**
+     * @param view The view to be dismissed
+     * @param velocity The desired pixels/second speed at which the view should move
+     * @param endAction The action to perform at the end
+     * @param delay The delay after which we should start
+     * @param useAccelerateInterpolator Should an accelerating Interpolator be used
+     * @param fixedDuration If not 0, this exact duration will be taken
+     */
+    public void dismissChild(final View view, float velocity, final Runnable endAction,
+            long delay, boolean useAccelerateInterpolator, long fixedDuration) {
         final View animView = mCallback.getChildContentView(view);
         final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
         float newPos;
@@ -289,22 +315,38 @@
         } else {
             newPos = getSize(animView);
         }
-        int duration = MAX_ESCAPE_ANIMATION_DURATION;
-        if (velocity != 0) {
-            duration = Math.min(duration,
-                                (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
-                                        .abs(velocity)));
+        long duration;
+        if (fixedDuration == 0) {
+            duration = MAX_ESCAPE_ANIMATION_DURATION;
+            if (velocity != 0) {
+                duration = Math.min(duration,
+                        (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
+                                .abs(velocity))
+                );
+            } else {
+                duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
+            }
         } else {
-            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
+            duration = fixedDuration;
         }
 
         animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         ObjectAnimator anim = createTranslationAnimation(animView, newPos);
-        anim.setInterpolator(sLinearInterpolator);
+        if (useAccelerateInterpolator) {
+            anim.setInterpolator(mFastOutLinearInInterpolator);
+        } else {
+            anim.setInterpolator(sLinearInterpolator);
+        }
         anim.setDuration(duration);
+        if (delay > 0) {
+            anim.setStartDelay(delay);
+        }
         anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animation) {
                 mCallback.onChildDismissed(view);
+                if (endAction != null) {
+                    endAction.run();
+                }
                 animView.setLayerType(View.LAYER_TYPE_NONE, null);
             }
         });
@@ -426,4 +468,15 @@
          */
         boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
     }
+
+    /**
+     * Equivalent to View.OnLongClickListener with coordinates
+     */
+    public interface LongPressListener {
+        /**
+         * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
+         * @return whether the longpress was handled
+         */
+        boolean onLongPress(View v, int x, int y);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 630ba13..b3f90d7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -46,8 +46,7 @@
             com.android.systemui.statusbar.SystemBars.class,
             com.android.systemui.usb.StorageNotification.class,
             com.android.systemui.power.PowerUI.class,
-            com.android.systemui.media.RingtonePlayer.class,
-            com.android.systemui.settings.SettingsUI.class,
+            com.android.systemui.media.RingtonePlayer.class
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 269b4ed..13c15f5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -16,20 +16,26 @@
 
 package com.android.systemui.doze;
 
+import static android.os.PowerManager.BRIGHTNESS_OFF;
+import static android.os.PowerManager.BRIGHTNESS_ON;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.hardware.TriggerEvent;
 import android.hardware.TriggerEventListener;
+import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.os.Vibrator;
-import android.service.dreams.DozeHardware;
 import android.service.dreams.DreamService;
 import android.util.Log;
+import android.util.MathUtils;
+import android.view.Display;
 
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
@@ -38,23 +44,27 @@
 import java.io.PrintWriter;
 
 public class DozeService extends DreamService {
-    private static final boolean DEBUG = false;
+    private static final String TAG = "DozeService";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final String TEASE_ACTION = "com.android.systemui.doze.tease";
 
-    private final String mTag = String.format("DozeService.%08x", hashCode());
+    private final String mTag = String.format(TAG + ".%08x", hashCode());
     private final Context mContext = this;
+    private final Handler mHandler = new Handler();
 
     private Host mHost;
-    private DozeHardware mDozeHardware;
     private SensorManager mSensors;
     private Sensor mSigMotionSensor;
     private PowerManager mPowerManager;
     private PowerManager.WakeLock mWakeLock;
+    private int mMaxBrightness;
     private boolean mDreaming;
     private boolean mTeaseReceiverRegistered;
     private boolean mSigMotionConfigured;
     private boolean mSigMotionEnabled;
+    private boolean mDisplayStateSupported;
+    private int mDisplayStateWhenOn;
 
     public DozeService() {
         if (DEBUG) Log.d(mTag, "new DozeService()");
@@ -65,11 +75,12 @@
     protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
         super.dumpOnHandler(fd, pw, args);
         pw.print("  mDreaming: "); pw.println(mDreaming);
-        pw.print("  mDozeHardware: "); pw.println(mDozeHardware);
         pw.print("  mTeaseReceiverRegistered: "); pw.println(mTeaseReceiverRegistered);
         pw.print("  mSigMotionSensor: "); pw.println(mSigMotionSensor);
         pw.print("  mSigMotionConfigured: "); pw.println(mSigMotionConfigured);
         pw.print("  mSigMotionEnabled: "); pw.println(mSigMotionEnabled);
+        pw.print("  mMaxBrightness: "); pw.println(mMaxBrightness);
+        pw.print("  mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
     }
 
     @Override
@@ -88,8 +99,16 @@
         mSigMotionSensor = mSensors.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
+        final Resources res = mContext.getResources();
         mSigMotionConfigured = SystemProperties.getBoolean("doze.tease.sigmotion",
-                mContext.getResources().getBoolean(R.bool.doze_tease_on_significant_motion));
+                res.getBoolean(R.bool.doze_tease_on_significant_motion));
+        mDisplayStateSupported = SystemProperties.getBoolean("doze.display.supported",
+                res.getBoolean(R.bool.doze_display_state_supported));
+        mMaxBrightness = MathUtils.constrain(res.getInteger(R.integer.doze_tease_brightness),
+                BRIGHTNESS_OFF, BRIGHTNESS_ON);
+
+        mDisplayStateWhenOn = mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON;
+        setDozeScreenState(mDisplayStateWhenOn);
     }
 
     @Override
@@ -101,9 +120,7 @@
     @Override
     public void onDreamingStarted() {
         super.onDreamingStarted();
-        mDozeHardware = getDozeHardware();
-        if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze()
-                + " dozeHardware=" + mDozeHardware);
+        if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze());
         mDreaming = true;
         listenForTeaseSignals(true);
         requestDoze();
@@ -112,9 +129,18 @@
     public void stayAwake(long millis) {
         if (mDreaming && millis > 0) {
             mWakeLock.acquire(millis);
+            setDozeScreenState(mDisplayStateWhenOn);
+            setDozeScreenBrightness(mMaxBrightness);
+            rescheduleOff(millis);
         }
     }
 
+    private void rescheduleOff(long millis) {
+        if (DEBUG) Log.d(TAG, "rescheduleOff millis=" + millis);
+        mHandler.removeCallbacks(mDisplayOff);
+        mHandler.postDelayed(mDisplayOff, millis);
+    }
+
     public void startDozing() {
         if (DEBUG) Log.d(mTag, "startDozing mDreaming=" + mDreaming);
         if (!mDreaming) {
@@ -131,7 +157,6 @@
         super.onDreamingStopped();
 
         mDreaming = false;
-        mDozeHardware = null;
         if (mWakeLock.isHeld()) {
             mWakeLock.release();
         }
@@ -225,6 +250,15 @@
         return sb.append(']').toString();
     }
 
+    private final Runnable mDisplayOff = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.d(TAG, "Display off");
+            setDozeScreenState(Display.STATE_OFF);
+            setDozeScreenBrightness(PowerManager.BRIGHTNESS_DEFAULT);
+        }
+    };
+
     private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
         @Override
         public void onTrigger(TriggerEvent event) {
@@ -252,6 +286,11 @@
         @Override
         public void onNewNotifications() {
             if (DEBUG) Log.d(mTag, "onNewNotifications");
+            // noop for now
+        }
+        @Override
+        public void onBuzzBeepBlinked() {
+            if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked");
             requestTease();
         }
     };
@@ -265,6 +304,7 @@
 
         public interface Callback {
             void onNewNotifications();
+            void onBuzzBeepBlinked();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index d76a2fe..42da282 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -93,10 +93,10 @@
         final Resources r = mContext.getResources();
         state.iconId = cb.noSim
                 ? R.drawable.stat_sys_no_sim
-                : cb.enabled && (cb.mobileSignalIconId > 0)
+                : cb.enabled && (cb.mobileSignalIconId > 0) && !cb.airplaneModeEnabled
                 ? cb.mobileSignalIconId
                 : R.drawable.ic_qs_signal_no_signal;
-        state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
+        state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiConnected
                 ? cb.dataTypeIconId
                 : 0;
         state.filter = state.iconId != R.drawable.stat_sys_no_sim;
@@ -132,6 +132,8 @@
     private static final class CallbackInfo {
         boolean enabled;
         boolean wifiEnabled;
+        boolean wifiConnected;
+        boolean airplaneModeEnabled;
         int mobileSignalIconId;
         String signalContentDescription;
         int dataTypeIconId;
@@ -144,12 +146,15 @@
 
     private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
         private boolean mWifiEnabled;
+        private boolean mWifiConnected;
+        private boolean mAirplaneModeEnabled;
 
         @Override
-        public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+        public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId,
                 boolean activityIn, boolean activityOut,
                 String wifiSignalContentDescriptionId, String description) {
             mWifiEnabled = enabled;
+            mWifiConnected = connected;
         }
 
         @Override
@@ -161,6 +166,8 @@
             final CallbackInfo info = new CallbackInfo();  // TODO pool?
             info.enabled = enabled;
             info.wifiEnabled = mWifiEnabled;
+            info.wifiConnected = mWifiConnected;
+            info.airplaneModeEnabled = mAirplaneModeEnabled;
             info.mobileSignalIconId = mobileSignalIconId;
             info.signalContentDescription = mobileSignalContentDescriptionId;
             info.dataTypeIconId = dataTypeIconId;
@@ -174,7 +181,7 @@
 
         @Override
         public void onAirplaneModeChanged(boolean enabled) {
-            // noop
+            mAirplaneModeEnabled = enabled;
         }
 
         public void onMobileDataEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 35dfdda..e0b465e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -24,7 +24,6 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 /** Quick settings tile: Hotspot **/
 public class HotspotTile extends QSTile<QSTile.BooleanState> {
@@ -32,14 +31,12 @@
     private static final long MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
 
     private final HotspotController mController;
-    private final KeyguardMonitor mKeyguard;
     private final Callback mCallback = new Callback();
     private final long mTimeToShowTile;
 
     public HotspotTile(Host host) {
         super(host);
         mController = host.getHotspotController();
-        mKeyguard = host.getKeyguardMonitor();
 
         mTimeToShowTile = MILLIS_PER_DAY
                 * mContext.getResources().getInteger(R.integer.days_to_show_hotspot);
@@ -54,10 +51,8 @@
     public void setListening(boolean listening) {
         if (listening) {
             mController.addCallback(mCallback);
-            mKeyguard.addCallback(mCallback);
         } else {
             mController.removeCallback(mCallback);
-            mKeyguard.removeCallback(mCallback);
         }
     }
 
@@ -69,8 +64,7 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
-        state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing())
-                && mController.isHotspotSupported() && isHotspotRecentlyUsed();
+        state.visible = mController.isHotspotSupported() && isHotspotRecentlyUsed();
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
         state.value = mController.isHotspotEnabled();
@@ -87,16 +81,11 @@
         return context.getSharedPreferences(context.getPackageName(), 0);
     }
 
-    private final class Callback implements HotspotController.Callback, KeyguardMonitor.Callback {
+    private final class Callback implements HotspotController.Callback {
         @Override
         public void onHotspotChanged(boolean enabled) {
             refreshState();
         }
-
-        @Override
-        public void onKeyguardChanged() {
-            refreshState();
-        }
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 900c7b26..1707b32 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -143,6 +143,7 @@
 
     private static final class CallbackInfo {
         boolean enabled;
+        boolean connected;
         int wifiSignalIconId;
         String enabledDesc;
         boolean activityIn;
@@ -153,6 +154,7 @@
         public String toString() {
             return new StringBuilder("CallbackInfo[")
                 .append("enabled=").append(enabled)
+                .append(",connected=").append(connected)
                 .append(",wifiSignalIconId=").append(wifiSignalIconId)
                 .append(",enabledDesc=").append(enabledDesc)
                 .append(",activityIn=").append(activityIn)
@@ -164,12 +166,13 @@
 
     private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
         @Override
-        public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+        public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId,
                 boolean activityIn, boolean activityOut,
                 String wifiSignalContentDescriptionId, String description) {
             if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
             final CallbackInfo info = new CallbackInfo();
             info.enabled = enabled;
+            info.connected = connected;
             info.wifiSignalIconId = wifiSignalIconId;
             info.enabledDesc = description;
             info.activityIn = activityIn;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 72a3341..25a62ae 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -56,9 +56,7 @@
 
     public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
-        float densityScale = getResources().getDisplayMetrics().density;
-        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
-        mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
+        mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, context);
         mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
         mRecycledViews = new HashSet<View>();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 1213375..e8e9d52 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -56,9 +56,7 @@
 
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
-        float densityScale = getResources().getDisplayMetrics().density;
-        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context);
 
         mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
         mRecycledViews = new HashSet<View>();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 591149c..cbcacc4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -133,7 +133,7 @@
                 intent.setPackage(mContext.getPackageName());
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                 intent.putExtra(RecentsActivity.EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
-                mContext.sendBroadcast(intent);
+                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
             }
         }
     }
@@ -222,7 +222,7 @@
             Intent intent = new Intent(RecentsActivity.ACTION_TOGGLE_RECENTS_ACTIVITY);
             intent.setPackage(mContext.getPackageName());
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-            mContext.sendBroadcast(intent);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
             mLastToggleTime = System.currentTimeMillis();
             return;
         } else {
@@ -444,7 +444,7 @@
             Intent intent = new Intent(RecentsActivity.ACTION_START_ENTER_ANIMATION);
             intent.setPackage(mContext.getPackageName());
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-            mContext.sendBroadcast(intent);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
             mStartAnimationTriggered = true;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 7d69b94..18dad3a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -431,6 +431,9 @@
         super.onNewIntent(intent);
         setIntent(intent);
 
+        // Reinitialize the configuration
+        RecentsConfiguration.reinitialize(this, RecentsTaskLoader.getInstance().getSystemServicesProxy());
+
         // Clear any debug rects
         if (mDebugOverlay != null) {
             mDebugOverlay.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 55711cf0..36d06d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -80,6 +80,7 @@
     public int taskViewTranslationZIncrementPx;
     public int taskViewRoundedCornerRadiusPx;
     public int taskViewHighlightPx;
+    public int taskViewAffiliateGroupEnterOffsetPx;
 
     /** Task bar colors */
     public int taskBarViewDefaultBackgroundColor;
@@ -210,6 +211,8 @@
         taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
         taskViewTranslationZIncrementPx =
                 res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment);
+        taskViewAffiliateGroupEnterOffsetPx =
+                res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset);
 
         // Task bar colors
         taskBarViewDefaultBackgroundColor =
@@ -305,6 +308,11 @@
                 (!transposeRecentsLayoutWithOrientation || !isLandscape);
     }
 
+    /** Returns whether the current layout is horizontal. */
+    public boolean hasHorizontalLayout() {
+        return isLandscape && transposeRecentsLayoutWithOrientation;
+    }
+
     /**
      * Returns the task stack bounds in the current orientation. These bounds do not account for
      * the system insets.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
index 9791038..326485e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
@@ -53,6 +53,18 @@
         return mTaskKeyIndices.get(t.key);
     }
 
+    /** Returns whether a task is in this grouping. */
+    public boolean containsTask(Task t) {
+        return mTaskKeyIndices.containsKey(t.key);
+    }
+
+    /** Returns whether one task is above another in the group.  If they are not in the same group,
+     * this returns false. */
+    public boolean isTaskAboveTask(Task t, Task below) {
+        return mTaskKeyIndices.containsKey(t.key) && mTaskKeyIndices.containsKey(below.key) &&
+                mTaskKeyIndices.get(t.key) > mTaskKeyIndices.get(below.key);
+    }
+
     /** Returns the number of tasks in this group. */
     public int getTaskCount() { return mTaskKeys.size(); }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 9076818..34f73c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.views;
 
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.view.View;
@@ -34,6 +35,7 @@
     int mCornerRadius;
 
     ObjectAnimator mClipTopAnimator;
+    ObjectAnimator mClipRightAnimator;
     ObjectAnimator mClipBottomAnimator;
 
     public AnimateableViewBounds(View source, int cornerRadius) {
@@ -42,6 +44,7 @@
         mCornerRadius = cornerRadius;
         mSourceView.setClipToOutline(true);
         setClipTop(getClipTop());
+        setClipRight(getClipRight());
         setClipBottom(getClipBottom());
         setOutlineClipBottom(getOutlineClipBottom());
     }
@@ -56,7 +59,7 @@
     }
 
     /** Animates the top clip. */
-    void animateClipTop(int top, int duration) {
+    void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
         if (mClipTopAnimator != null) {
             mClipTopAnimator.removeAllListeners();
             mClipTopAnimator.cancel();
@@ -64,6 +67,9 @@
         mClipTopAnimator = ObjectAnimator.ofInt(this, "clipTop", top);
         mClipTopAnimator.setDuration(duration);
         mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
+        if (updateListener != null) {
+            mClipTopAnimator.addUpdateListener(updateListener);
+        }
         mClipTopAnimator.start();
     }
 
@@ -80,16 +86,41 @@
         return mClipRect.top;
     }
 
+    /** Animates the right clip. */
+    void animateClipRight(int right, int duration) {
+        if (mClipRightAnimator != null) {
+            mClipRightAnimator.removeAllListeners();
+            mClipRightAnimator.cancel();
+        }
+        mClipRightAnimator = ObjectAnimator.ofInt(this, "clipRight", right);
+        mClipRightAnimator.setDuration(duration);
+        mClipRightAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
+        mClipRightAnimator.start();
+    }
+
+    /** Sets the right clip. */
+    public void setClipRight(int right) {
+        if (right != mClipRect.right) {
+            mClipRect.right = right;
+            mSourceView.invalidateOutline();
+        }
+    }
+
+    /** Returns the right clip. */
+    public int getClipRight() {
+        return mClipRect.right;
+    }
+
     /** Animates the bottom clip. */
     void animateClipBottom(int bottom, int duration) {
-        if (mClipTopAnimator != null) {
-            mClipTopAnimator.removeAllListeners();
-            mClipTopAnimator.cancel();
+        if (mClipBottomAnimator != null) {
+            mClipBottomAnimator.removeAllListeners();
+            mClipBottomAnimator.cancel();
         }
-        mClipTopAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom);
-        mClipTopAnimator.setDuration(duration);
-        mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
-        mClipTopAnimator.start();
+        mClipBottomAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom);
+        mClipBottomAnimator.setDuration(duration);
+        mClipBottomAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
+        mClipBottomAnimator.start();
     }
 
     /** Sets the bottom clip. */
@@ -105,6 +136,7 @@
         return mClipRect.bottom;
     }
 
+    /** Sets the outline bottom clip. */
     public void setOutlineClipBottom(int bottom) {
         if (bottom != mOutlineClipRect.bottom) {
             mOutlineClipRect.bottom = bottom;
@@ -112,6 +144,7 @@
         }
     }
 
+    /** Gets the outline bottom clip. */
     public int getOutlineClipBottom() {
         return mOutlineClipRect.bottom;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 356841f..189578c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -449,7 +449,7 @@
         if (tv == null) {
             post(launchRunnable);
         } else {
-            stackView.animateOnLaunchingTask(tv, launchRunnable);
+            stackView.startLaunchTaskAnimation(tv, launchRunnable);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index fd636ed..dc8f0db 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -163,6 +163,7 @@
         } else if (t.applicationIcon != null) {
             mApplicationIcon.setImageDrawable(t.applicationIcon);
         }
+        mApplicationIcon.setContentDescription(t.activityLabel);
         if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
             mActivityDescription.setText(t.activityLabel);
         }
@@ -176,6 +177,9 @@
                 mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor);
         mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
                 mLightDismissDrawable : mDarkDismissDrawable);
+        mDismissButton.setContentDescription(
+                getContext().getString(R.string.accessibility_recents_item_will_be_dismissed,
+                        t.activityLabel));
     }
 
     /** Unbinds the bar view from the task */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java
index 95af1c9..881bbcf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java
@@ -16,12 +16,9 @@
 
 package com.android.systemui.recents.views;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.View;
 import android.widget.FrameLayout;
 import com.android.systemui.recents.RecentsConfiguration;
 
@@ -82,9 +79,6 @@
     void animateFooterVisibility(final boolean visible, int duration) {
         // Return early if there is no footer
         if (mMaxFooterHeight <= 0) return;
-        // Return early if we are already in the final state
-        if (!visible && getVisibility() != View.VISIBLE) return;
-        if (visible && getVisibility() == View.VISIBLE) return;
 
         // Cancel the previous animation
         if (mFooterAnimator != null) {
@@ -93,25 +87,12 @@
         }
         int finalHeight = visible ? mMaxFooterHeight : 0;
         if (duration > 0) {
-            // Make the view visible for the animation
-            if (visible && getVisibility() != View.VISIBLE) {
-                setVisibility(View.VISIBLE);
-            }
             mFooterAnimator = ObjectAnimator.ofInt(this, "footerHeight", finalHeight);
             mFooterAnimator.setDuration(duration);
             mFooterAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
-            mFooterAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (!visible) {
-                        setVisibility(View.INVISIBLE);
-                    }
-                }
-            });
             mFooterAnimator.start();
         } else {
             setFooterHeight(finalHeight);
-            setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index f135e32..ba90af3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -27,12 +27,12 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 import android.widget.OverScroller;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.Utilities;
@@ -83,7 +83,6 @@
     int mFocusedTaskIndex = -1;
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
-    boolean mEnableStackClipping = true;
 
     // Optimizations
     ReferenceCountedTrigger mHwLayersTrigger;
@@ -93,8 +92,6 @@
     boolean mStartEnterAnimationRequestedAfterLayout;
     ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
     int[] mTmpVisibleRange = new int[2];
-    Rect mTmpRect = new Rect();
-    Rect mTmpRect2 = new Rect();
     TaskViewTransform mTmpTransform = new TaskViewTransform();
     HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<Task, TaskView>();
     LayoutInflater mInflater;
@@ -189,7 +186,7 @@
                                        int stackScroll,
                                        int[] visibleRangeOut,
                                        boolean boundTranslationsToRect) {
-        // XXX: We should be intelligent about wheee to look for the visible stack range using the
+        // XXX: We should be intelligent about where to look for the visible stack range using the
         //      current stack scroll.
         // XXX: We should log extra cases like the ones below where we don't expect to hit very often
         // XXX: Print out approximately how many indices we have to go through to find the first visible transform
@@ -199,8 +196,6 @@
         int frontMostVisibleIndex = -1;
         int backMostVisibleIndex = -1;
 
-
-
         // We can reuse the task transforms where possible to reduce object allocation
         if (taskTransformCount < taskCount) {
             // If there are less transforms than tasks, then add as many transforms as necessary
@@ -290,6 +285,7 @@
 
                 if (tv == null) {
                     tv = mViewPool.pickUpViewFromPool(task, task);
+
                     if (mStackViewsAnimationDuration > 0) {
                         // For items in the list, put them in start animating them from the
                         // approriate ends of the list where they are expected to appear
@@ -319,7 +315,7 @@
     /** Updates the clip for each of the task views. */
     void clipTaskViews() {
         // Update the clip on each task child
-        if (Constants.DebugFlags.App.EnableTaskStackClipping && mEnableStackClipping) {
+        if (Constants.DebugFlags.App.EnableTaskStackClipping) {
             int childCount = getChildCount();
             for (int i = 0; i < childCount - 1; i++) {
                 TaskView tv = (TaskView) getChildAt(i);
@@ -341,12 +337,10 @@
                     // stacked and we can make assumptions about the visibility of the this
                     // task relative to the ones in front of it.
                     if (nextTv != null) {
-                        // We calculate the bottom clip independent of the footer (since we animate
-                        // that)
-                        int scaledMaxFooterHeight = (int) (tv.getMaxFooterHeight() * tv.getScaleX());
-                        tv.getHitRect(mTmpRect);
-                        nextTv.getHitRect(mTmpRect2);
-                        clipBottom = (mTmpRect.bottom - scaledMaxFooterHeight - mTmpRect2.top);
+                        // We can reuse the current task transforms to find the task rects
+                        TaskViewTransform transform = mCurrentTaskTransforms.get(mStack.indexOfTask(tv.getTask()));
+                        TaskViewTransform nextTransform = mCurrentTaskTransforms.get(mStack.indexOfTask(nextTv.getTask()));
+                        clipBottom = transform.rect.bottom - nextTransform.rect.top - 200;
                     }
                 }
                 tv.getViewBounds().setClipBottom(clipBottom);
@@ -359,18 +353,6 @@
         }
     }
 
-    /** Enables/Disables clipping of the tasks in the stack. */
-    void setStackClippingEnabled(boolean stackClippingEnabled) {
-        if (!stackClippingEnabled) {
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                TaskView tv = (TaskView) getChildAt(i);
-                tv.getViewBounds().setClipBottom(0);
-            }
-        }
-        mEnableStackClipping = stackClippingEnabled;
-    }
-
     /** The stack insets to apply to the stack contents */
     public void setStackInsetRect(Rect r) {
         mTaskStackBounds.set(r);
@@ -513,20 +495,6 @@
         }
     }
 
-    /** Animates a task view in this stack as it launches. */
-    public void animateOnLaunchingTask(TaskView tv, final Runnable r) {
-        // Hide each of the task bar dismiss buttons
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView t = (TaskView) getChildAt(i);
-            if (t == tv) {
-                t.startLaunchTaskAnimation(r, true);
-            } else {
-                t.startLaunchTaskAnimation(null, false);
-            }
-        }
-    }
-
     /** Focuses the task at the specified index in the stack */
     void focusTask(int taskIndex, boolean scrollToNewPosition) {
         if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
@@ -634,18 +602,6 @@
             setStackScrollToInitialState();
             requestSynchronizeStackViewsWithModel();
             synchronizeStackViewsWithModel();
-
-            // Find the first task and mark it as full screen
-            if (mConfig.launchedFromAppWithScreenshot) {
-                int childCount = getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    TaskView tv = (TaskView) getChildAt(i);
-                    if (tv.getTask().isLaunchTarget) {
-                        tv.setIsFullScreen(true);
-                        break;
-                    }
-                }
-            }
         }
 
         // Measure each of the TaskViews
@@ -694,13 +650,28 @@
 
     /** Handler for the first layout. */
     void onFirstLayout() {
-        // Prepare the first view for its enter animation
         int offscreenY = mStackAlgorithm.mViewRect.bottom -
                 (mStackAlgorithm.mTaskRect.top - mStackAlgorithm.mViewRect.top);
+
+        // Find the launch target task
+        Task launchTargetTask = null;
         int childCount = getChildCount();
         for (int i = childCount - 1; i >= 0; i--) {
             TaskView tv = (TaskView) getChildAt(i);
-            tv.prepareEnterRecentsAnimation(tv.getTask().isLaunchTarget, offscreenY);
+            Task task = tv.getTask();
+            if (task.isLaunchTarget) {
+                launchTargetTask = task;
+                break;
+            }
+        }
+
+        // Prepare the first view for its enter animation
+        for (int i = childCount - 1; i >= 0; i--) {
+            TaskView tv = (TaskView) getChildAt(i);
+            Task task = tv.getTask();
+            boolean occludesLaunchTarget = (launchTargetTask != null) &&
+                    launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
+            tv.prepareEnterRecentsAnimation(task.isLaunchTarget, occludesLaunchTarget, offscreenY);
         }
 
         // If the enter animation started already and we haven't completed a layout yet, do the
@@ -728,15 +699,28 @@
         }
 
         if (mStack.getTaskCount() > 0) {
-            // Animate all the task views into view
+            // Find the launch target task
+            Task launchTargetTask = null;
             int childCount = getChildCount();
             for (int i = childCount - 1; i >= 0; i--) {
                 TaskView tv = (TaskView) getChildAt(i);
                 Task task = tv.getTask();
+                if (task.isLaunchTarget) {
+                    launchTargetTask = task;
+                    break;
+                }
+            }
+
+            // Animate all the task views into view
+            for (int i = childCount - 1; i >= 0; i--) {
+                TaskView tv = (TaskView) getChildAt(i);
+                Task task = tv.getTask();
                 ctx.currentTaskTransform = new TaskViewTransform();
                 ctx.currentStackViewIndex = i;
                 ctx.currentStackViewCount = childCount;
                 ctx.currentTaskRect = mStackAlgorithm.mTaskRect;
+                ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
+                        launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
                 mStackAlgorithm.getStackTransform(task, getStackScroll(), ctx.currentTaskTransform);
                 tv.startEnterRecentsAnimation(ctx);
             }
@@ -747,11 +731,6 @@
                 public void run() {
                     // Start dozing
                     mUIDozeTrigger.startDozing();
-                    // Request an update of the task views after the animation in to 
-                    // relayout the fullscreen view back to its normal size
-                    if (mConfig.launchedFromAppWithScreenshot) {
-                        requestSynchronizeStackViewsWithModel();
-                    }
                 }
             });
         }
@@ -772,6 +751,24 @@
         ctx.postAnimationTrigger.addLastDecrementRunnable(mReturnAllViewsToPoolRunnable);
     }
 
+    /** Animates a task view in this stack as it launches. */
+    public void startLaunchTaskAnimation(TaskView tv, final Runnable r) {
+        Task launchTargetTask = tv.getTask();
+        int offscreenTranslationY = mStackAlgorithm.mViewRect.bottom -
+                (mStackAlgorithm.mTaskRect.top - mStackAlgorithm.mViewRect.top);
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TaskView t = (TaskView) getChildAt(i);
+            if (t == tv) {
+                t.startLaunchTaskAnimation(r, true, true);
+            } else {
+                boolean occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(t.getTask(),
+                        launchTargetTask);
+                t.startLaunchTaskAnimation(null, false, occludesLaunchTarget);
+            }
+        }
+    }
+
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
@@ -925,6 +922,15 @@
     public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) {
         // Rebind the task and request that this task's data be filled into the TaskView
         tv.onTaskBound(task);
+
+        // Mark the launch task as fullscreen
+        if (Constants.DebugFlags.App.EnableScreenshotAppTransition && mAwaitingFirstLayout) {
+            if (task.isLaunchTarget) {
+                tv.setIsFullScreen(true);
+            }
+        }
+
+        // Load the task data
         RecentsTaskLoader.getInstance().loadTaskData(task);
 
         // Sanity check, the task view should always be clipping against the stack at this point,
@@ -1000,6 +1006,9 @@
     @Override
     public void onTaskViewDismissed(TaskView tv) {
         Task task = tv.getTask();
+        // Announce for accessibility
+        tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed,
+                tv.getTask().activityLabel));
         // Remove the task from the view
         mStack.removeTask(task);
     }
@@ -1009,6 +1018,11 @@
         invalidate(mStackAlgorithm.mStackRect);
     }
 
+    @Override
+    public void onTaskViewFullScreenTransitionCompleted() {
+        requestSynchronizeStackViewsWithModel();
+    }
+
     /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
 
     @Override
@@ -1034,4 +1048,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 7f94a0a..0fd4e86 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -82,7 +82,7 @@
         // Compute the min and max scroll values
         int numTasks = Math.max(1, tasks.size());
         int taskHeight = mTaskRect.height();
-        int stackHeight = mStackRect.height();
+        int stackHeight = mStackRectSansPeek.height();
 
         if (numTasks <= 1) {
             // If there is only one task, then center the task in the stack rect (sans peek)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index b83f9cc..b1c35f3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -263,7 +263,6 @@
                 int velocity = (int) velocityTracker.getYVelocity(mActivePointerId);
 
                 if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
-                    // XXX: Make this animation a function of the velocity AND distance
                     int overscrollRange = (int) (Math.min(1f,
                             Math.abs((float) velocity / mMaximumVelocity)) *
                             Constants.Values.TaskStackView.TaskStackOverscrollRange);
@@ -277,7 +276,6 @@
                     mSv.invalidate(mSv.mStackAlgorithm.mStackRect);
                 } else if (mSv.isScrollOutOfBounds()) {
                     // Animate the scroll back into bounds
-                    // XXX: Make this animation a function of the velocity OR distance
                     mSv.animateBoundScroll();
                 }
 
@@ -303,7 +301,6 @@
             case MotionEvent.ACTION_CANCEL: {
                 if (mSv.isScrollOutOfBounds()) {
                     // Animate the scroll back into bounds
-                    // XXX: Make this animation a function of the velocity OR distance
                     mSv.animateBoundScroll();
                 }
                 mActivePointerId = INACTIVE_POINTER_ID;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 259706b..e97ce30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -21,7 +21,6 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
@@ -35,6 +34,7 @@
 import com.android.systemui.recents.AlternateRecentsComponent;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 
 /* A task view */
@@ -47,6 +47,7 @@
         public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
         public void onTaskViewDismissed(TaskView tv);
         public void onTaskViewClipStateChanged(TaskView tv);
+        public void onTaskViewFullScreenTransitionCompleted();
     }
 
     RecentsConfiguration mConfig;
@@ -60,7 +61,6 @@
     boolean mTaskDataLoaded;
     boolean mIsFocused;
     boolean mIsFullScreenView;
-    boolean mIsStub;
     boolean mClipViewInStack;
     AnimateableViewBounds mViewBounds;
     Paint mLayerPaint = new Paint();
@@ -123,7 +123,11 @@
         mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
         mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
         mFooterView = (TaskFooterView) findViewById(R.id.lock_to_app);
-        mFooterView.setCallbacks(this);
+        if (mConfig.lockToAppEnabled) {
+            mFooterView.setCallbacks(this);
+        } else {
+            mFooterView.setVisibility(View.GONE);
+        }
     }
 
     @Override
@@ -147,6 +151,7 @@
                     MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY));
         }
         setMeasuredDimension(width, height);
+        invalidateOutline();
     }
 
     /** Synchronizes this view's properties with the task's transform */
@@ -197,13 +202,15 @@
 
     /** Prepares this task view for the enter-recents animations.  This is called earlier in the
      * first layout because the actual animation into recents may take a long time. */
-    public void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, int offscreenY) {
+    public void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
+                                             boolean occludesLaunchTarget, int offscreenY) {
         if (mConfig.launchedFromAppWithScreenshot) {
             if (isTaskViewLaunchTargetTask) {
-                // Also hide the front most task bar view so we can animate it in
                 mBarView.prepareEnterRecentsAnimation();
+                // Hide the footer during the transition in, and animate it out afterwards?
+                mFooterView.animateFooterVisibility(false, 0);
             } else {
-                // Don't do anything for the side views
+                // Don't do anything for the side views when animating in
             }
 
         } else if (mConfig.launchedFromAppWithThumbnail) {
@@ -212,6 +219,9 @@
                 mBarView.prepareEnterRecentsAnimation();
                 // Set the dim to 0 so we can animate it in
                 setDim(0);
+            } else if (occludesLaunchTarget) {
+                // Move the task view off screen (below) so we can animate it in
+                setTranslationY(offscreenY);
             }
 
         } else if (mConfig.launchedFromHome) {
@@ -227,40 +237,68 @@
 
     /** Animates this task view as it enters recents */
     public void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) {
-        TaskViewTransform transform = ctx.currentTaskTransform;
-        Rect taskRect = ctx.currentTaskRect;
+        final TaskViewTransform transform = ctx.currentTaskTransform;
 
         if (mConfig.launchedFromAppWithScreenshot) {
             if (mTask.isLaunchTarget) {
-                // XXX: We would have to animate the trasnlationY of the task view bar along with the clip and
-                // reset it at the bottom
+                Rect taskRect = ctx.currentTaskRect;
+                int duration = mConfig.taskViewEnterFromHomeDuration * 10;
+                int windowInsetTop = mConfig.systemInsets.top; // XXX: Should be for the window
+                float taskScale = ((float) taskRect.width() / getMeasuredWidth()) * transform.scale;
+                float scaledYOffset = ((1f - taskScale) * getMeasuredHeight()) / 2;
+                float scaledWindowInsetTop = (int) (taskScale * windowInsetTop);
+                float scaledTranslationY = taskRect.top + transform.translationY -
+                        (scaledWindowInsetTop + scaledYOffset);
 
-                // XXX: This should actually be the inset on the current app...
-                mViewBounds.animateClipTop(taskRect.top, mConfig.taskViewEnterFromHomeDuration * 5);
-                mViewBounds.animateClipBottom(getMeasuredHeight() - taskRect.bottom, mConfig.taskViewEnterFromHomeDuration * 5);
-
-                animate().scaleX(((float) taskRect.width() / getMeasuredWidth()) * transform.scale)
-                        .scaleY(((float) taskRect.width() / getMeasuredWidth()) * transform.scale)
-                        .translationY(taskRect.top + transform.translationY)
-                        .setDuration(mConfig.taskViewEnterFromHomeDuration * 5)
+                // Animate the top clip
+                mViewBounds.animateClipTop(windowInsetTop, duration,
+                        new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        int y = (Integer) animation.getAnimatedValue();
+                        mBarView.setTranslationY(y);
+                    }
+                });
+                // Animate the bottom or right clip
+                int size = Math.round((taskRect.width() / taskScale));
+                if (mConfig.hasHorizontalLayout()) {
+                    mViewBounds.animateClipRight(getMeasuredWidth() - size, duration);
+                } else {
+                    mViewBounds.animateClipBottom(getMeasuredHeight() - (windowInsetTop + size), duration);
+                }
+                // Animate the task bar of the first task view
+                mBarView.startEnterRecentsAnimation(0, null);
+                animate()
+                        .scaleX(taskScale)
+                        .scaleY(taskScale)
+                        .translationY(scaledTranslationY)
+                        .setDuration(duration)
                         .withEndAction(new Runnable() {
                             @Override
                             public void run() {
-                                // Animate the task bar of the first task view
-                                mBarView.startEnterRecentsAnimation(0, mThumbnailView.enableTaskBarClipAsRunnable(mBarView));
+                                setIsFullScreen(false);
+                                requestLayout();
+
+                                // Reset the clip
+                                mViewBounds.setClipTop(0);
+                                mViewBounds.setClipBottom(0);
+                                mViewBounds.setClipRight(0);
+                                // Reset the bar translation
+                                mBarView.setTranslationY(0);
+                                // Enable the thumbnail clip
+                                mThumbnailView.enableTaskBarClip(mBarView);
                                 // Animate the footer into view (if it is the front most task)
                                 animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration);
-                                // Decrement the post animation trigger
-                                ctx.postAnimationTrigger.decrement();
 
-                                // XXX Request layout and only start hte next animation after the next
-                                // layout
-
-                                setIsFullScreen(false);
-                                mThumbnailView.unbindFromScreenshot();
-
+                                // Unbind the thumbnail from the screenshot
+                                RecentsTaskLoader.getInstance().loadTaskData(mTask);
                                 // Recycle the full screen screenshot
                                 AlternateRecentsComponent.consumeLastScreenshot();
+
+                                mCb.onTaskViewFullScreenTransitionCompleted();
+
+                                // Decrement the post animation trigger
+                                ctx.postAnimationTrigger.decrement();
                             }
                         })
                         .start();
@@ -297,7 +335,29 @@
                 // Animate the footer into view
                 animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration);
             } else {
+                // Enable the task bar clip
                 mThumbnailView.enableTaskBarClip(mBarView);
+                // Animate the task up if it was occluding the launch target
+                if (ctx.currentTaskOccludesLaunchTarget) {
+                    setTranslationY(transform.translationY + mConfig.taskViewAffiliateGroupEnterOffsetPx);
+                    setAlpha(0f);
+                    animate().alpha(1f)
+                            .translationY(transform.translationY)
+                            .setStartDelay(mConfig.taskBarEnterAnimDelay)
+                            .setUpdateListener(null)
+                            .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                            .setDuration(mConfig.taskViewEnterFromHomeDuration)
+                            .withEndAction(new Runnable() {
+                                @Override
+                                public void run() {
+                                    mThumbnailView.enableTaskBarClip(mBarView);
+                                    // Decrement the post animation trigger
+                                    ctx.postAnimationTrigger.decrement();
+                                }
+                            })
+                            .start();
+                    ctx.postAnimationTrigger.increment();
+                }
             }
 
         } else if (mConfig.launchedFromHome) {
@@ -353,7 +413,8 @@
     }
 
     /** Animates this task view as it exits recents */
-    public void startLaunchTaskAnimation(final Runnable r, boolean isLaunchingTask) {
+    public void startLaunchTaskAnimation(final Runnable r, boolean isLaunchingTask,
+                                         boolean occludesLaunchTarget) {
         if (isLaunchingTask) {
             // Disable the thumbnail clip and animate the bar out
             mBarView.startLaunchTaskAnimation(mThumbnailView.disableTaskBarClipAsRunnable(), r);
@@ -368,6 +429,17 @@
         } else {
             // Hide the dismiss button
             mBarView.startLaunchTaskDismissAnimation();
+            // If this is another view in the task grouping and is in front of the launch task,
+            // animate it away first
+            if (occludesLaunchTarget) {
+                animate().alpha(0f)
+                    .translationY(getTranslationY() + mConfig.taskViewAffiliateGroupEnterOffsetPx)
+                    .setStartDelay(0)
+                    .setUpdateListener(null)
+                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .start();
+            }
         }
     }
 
@@ -424,11 +496,6 @@
         return mIsFullScreenView;
     }
 
-    /** Sets the stubbed state of this task view. */
-    void setStubState(boolean isStub) {
-        mIsStub = isStub;
-    }
-
     /**
      * Returns whether this view should be clipped, or any views below should clip against this
      * view.
@@ -447,7 +514,11 @@
 
     /** Gets the max footer height. */
     public int getMaxFooterHeight() {
-        return mFooterView.mMaxFooterHeight;
+        if (mConfig.lockToAppEnabled) {
+            return mFooterView.mMaxFooterHeight;
+        } else {
+            return 0;
+        }
     }
 
     /** Animates the footer into and out of view. */
@@ -488,17 +559,6 @@
         setDim(getDimOverlayFromScale());
     }
 
-    /**** View drawing ****/
-
-    @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        if (mIsStub && (child != mBarView)) {
-            // Skip the thumbnail view if we are in stub mode
-            return false;
-        }
-        return super.drawChild(canvas, child, drawingTime);
-    }
-
     /**** View focus state ****/
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
index 3705cb5..a1fc40f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -30,6 +30,8 @@
 
         // These following properties are updated for each task view we start the enter animation on
 
+        // Whether or not the current task occludes the launch target
+        boolean currentTaskOccludesLaunchTarget;
         // The task rect for the current stack
         Rect currentTaskRect;
         // The transform of the current task view
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 6d5bb9d..108c8df 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -163,15 +163,17 @@
         if (mListening) {
             return;
         }
+
         mBrightnessObserver.startObserving();
         mUserTracker.startTracking();
 
-        // Update the slider and mode before attaching the listener so we don't receive the
-        // onChanged notifications for the initial values.
+        // Update the slider and mode before attaching the listener so we don't
+        // receive the onChanged notifications for the initial values.
         updateMode();
         updateSlider();
 
         mControl.setOnChangedListener(this);
+        mListening = true;
     }
 
     /** Unregister all call backs, both to and from the controller */
@@ -179,10 +181,11 @@
         if (!mListening) {
             return;
         }
+
         mBrightnessObserver.stopObserving();
-        mChangeCallbacks.clear();
         mUserTracker.stopTracking();
         mControl.setOnChangedListener(null);
+        mListening = false;
     }
 
     public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 65e1cc6..d113139 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.settings;
 
+import android.app.Activity;
 import android.app.Dialog;
 import android.content.Context;
 import android.content.res.Resources;
@@ -30,99 +31,55 @@
 import com.android.systemui.R;
 
 /** A dialog that provides controls for adjusting the screen brightness. */
-public class BrightnessDialog extends Dialog implements
-        BrightnessController.BrightnessStateChangeCallback {
-
-    private static final String TAG = "BrightnessDialog";
-    private static final boolean DEBUG = false;
-
-    protected Handler mHandler = new Handler();
+public class BrightnessDialog extends Activity {
 
     private BrightnessController mBrightnessController;
-    private final int mBrightnessDialogLongTimeout;
-    private final int mBrightnessDialogShortTimeout;
 
-    private final Runnable mDismissDialogRunnable = new Runnable() {
-        public void run() {
-            if (BrightnessDialog.this.isShowing()) {
-                BrightnessDialog.this.dismiss();
-            }
-        };
-    };
-
-
-    public BrightnessDialog(Context ctx) {
-        super(ctx);
-        Resources r = ctx.getResources();
-        mBrightnessDialogLongTimeout =
-                r.getInteger(R.integer.quick_settings_brightness_dialog_long_timeout);
-        mBrightnessDialogShortTimeout =
-                r.getInteger(R.integer.quick_settings_brightness_dialog_short_timeout);
-    }
-
-
-    /**
-     * Create the brightness dialog and any resources that are used for the
-     * entire lifetime of the dialog.
-     */
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Window window = getWindow();
-        window.setGravity(Gravity.TOP);
-        WindowManager.LayoutParams lp = window.getAttributes();
+
+        final Window window = getWindow();
+        final WindowManager.LayoutParams lp = window.getAttributes();
+
         // Offset from the top
-        lp.y = getContext().getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
+        lp.y = getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
         lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
-        lp.privateFlags |=
-                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+
         window.setAttributes(lp);
+        window.setGravity(Gravity.TOP);
         window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         window.requestFeature(Window.FEATURE_NO_TITLE);
 
         setContentView(R.layout.quick_settings_brightness_dialog);
-        setCanceledOnTouchOutside(true);
     }
 
-
     @Override
     protected void onStart() {
         super.onStart();
-        mBrightnessController = new BrightnessController(getContext(),
-                (ImageView) findViewById(R.id.brightness_icon),
-                (ToggleSlider) findViewById(R.id.brightness_slider));
+
+        final ImageView icon = (ImageView) findViewById(R.id.brightness_icon);
+        final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider);
+        mBrightnessController = new BrightnessController(this, icon, slider);
         mBrightnessController.registerCallbacks();
-        dismissBrightnessDialog(mBrightnessDialogLongTimeout);
-        mBrightnessController.addStateChangedCallback(this);
     }
 
     @Override
     protected void onStop() {
         super.onStop();
+
         mBrightnessController.unregisterCallbacks();
-        removeAllBrightnessDialogCallbacks();
-    }
-
-    public void onBrightnessLevelChanged() {
-        dismissBrightnessDialog(mBrightnessDialogShortTimeout);
-    }
-
-    private void dismissBrightnessDialog(int timeout) {
-        removeAllBrightnessDialogCallbacks();
-        mHandler.postDelayed(mDismissDialogRunnable, timeout);
-    }
-
-    private void removeAllBrightnessDialogCallbacks() {
-        mHandler.removeCallbacks(mDismissDialogRunnable);
     }
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
-                keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
-                keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
-            dismiss();
+        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                || keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
+            finish();
         }
+
         return super.onKeyDown(keyCode, event);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java b/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java
deleted file mode 100644
index 8bc72c9..0000000
--- a/packages/SystemUI/src/com/android/systemui/settings/SettingsUI.java
+++ /dev/null
@@ -1,77 +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 com.android.systemui.settings;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.util.Log;
-
-import com.android.systemui.SystemUI;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-public class SettingsUI extends SystemUI {
-    private static final String TAG = "SettingsUI";
-    private static final boolean DEBUG = false;
-
-    private final Handler mHandler = new Handler();
-    private BrightnessDialog mBrightnessDialog;
-
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)) {
-                if (DEBUG) Log.d(TAG, "showing brightness dialog");
-
-                if (mBrightnessDialog == null) {
-                    mBrightnessDialog = new BrightnessDialog(mContext);
-                    mBrightnessDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
-                        @Override
-                        public void onDismiss(DialogInterface dialog) {
-                            mBrightnessDialog = null;
-                        }
-                    });
-                }
-
-                if (!mBrightnessDialog.isShowing()) {
-                    mBrightnessDialog.show();
-                }
-
-            } else {
-                Log.w(TAG, "unknown intent: " + intent);
-            }
-        }
-    };
-
-    public void start() {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
-        mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, mHandler);
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.print("mBrightnessDialog=");
-        pw.println(mBrightnessDialog == null ? "null" : mBrightnessDialog.toString());
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 0a288d9..48fc4ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.Notification;
@@ -33,6 +36,7 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Build;
@@ -57,18 +61,17 @@
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.LayoutInflater;
-import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewAnimationUtils;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewStub;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.view.animation.AnimationUtils;
 import android.widget.DateTimeView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.PopupMenu;
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
@@ -79,6 +82,7 @@
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SearchPanelView;
+import com.android.systemui.SwipeHelper;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
@@ -141,8 +145,6 @@
     // Search panel
     protected SearchPanelView mSearchPanelView;
 
-    protected PopupMenu mNotificationBlamePopup;
-
     protected int mCurrentUserId = 0;
     final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
 
@@ -184,6 +186,11 @@
 
     protected int mZenMode;
 
+    // which notification is currently being longpress-examined by the user
+    private View mNotificationGutsExposed;
+
+    private TimeInterpolator mLinearOutSlowIn, mFastOutLinearIn;
+
     /**
      * The {@link StatusBarState} of the status bar.
      */
@@ -192,6 +199,7 @@
     protected boolean mShowLockscreenNotifications;
 
     protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
+    protected DismissView mDismissView;
 
     public boolean isDeviceProvisioned() {
         return mDeviceProvisioned;
@@ -244,9 +252,6 @@
                             // the user switches to home.  We know it is safe to do at this
                             // point, so make sure new activity switches are now allowed.
                             ActivityManagerNative.getDefault().resumeAppSwitches();
-                            // Also, notifications can be launched from the lock screen,
-                            // so dismiss the lock screen when the activity starts.
-                            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
                         } catch (RemoteException e) {
                         }
 
@@ -418,6 +423,11 @@
 
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
 
+        mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.linear_out_slow_in);
+        mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.fast_out_linear_in);
+
         // Connect in to the status bar manager service
         StatusBarIconList iconList = new StatusBarIconList();
         mCommandQueue = new CommandQueue(this, iconList);
@@ -595,29 +605,61 @@
                 null, UserHandle.CURRENT);
     }
 
-    protected View.OnLongClickListener getNotificationLongClicker() {
-        return new View.OnLongClickListener() {
+    private static final int max(int...args) {
+        switch (args.length) {
+            case 0:
+                return 0;
+            case 1:
+                return args[0];
+            case 2:
+                return args[1] > args[0] ? args[1] : args[0];
+            default:
+                int m = args[0];
+                for (int i = 0; i < args.length; i++) {
+                    if (args[i] > m) {
+                        m = args[i];
+                    }
+                }
+                return m;
+        }
+    }
+
+    protected SwipeHelper.LongPressListener getNotificationLongClicker() {
+        return new SwipeHelper.LongPressListener() {
             @Override
-            public boolean onLongClick(View v) {
+            public boolean onLongPress(View v, int x, int y) {
+                dismissPopups();
+
                 final String packageNameF = (String) v.getTag();
                 if (packageNameF == null) return false;
                 if (v.getWindowToken() == null) return false;
-                mNotificationBlamePopup = new PopupMenu(mContext, v);
-                mNotificationBlamePopup.getMenuInflater().inflate(
-                        R.menu.notification_popup_menu,
-                        mNotificationBlamePopup.getMenu());
-                mNotificationBlamePopup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
-                    public boolean onMenuItemClick(MenuItem item) {
-                        if (item.getItemId() == R.id.notification_inspect_item) {
-                            startApplicationDetailsActivity(packageNameF);
-                            animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
-                        } else {
-                            return false;
-                        }
-                        return true;
+
+                // Assume we are a status_bar_notification_row
+                final View guts = v.findViewById(R.id.notification_guts);
+                if (guts == null) return false;
+
+                // Already showing?
+                if (guts.getVisibility() == View.VISIBLE) return false;
+
+                final View button = guts.findViewById(R.id.notification_inspect_item);
+                button.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        startApplicationDetailsActivity(packageNameF);
+                        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
                     }
                 });
-                mNotificationBlamePopup.show();
+
+                guts.setVisibility(View.VISIBLE);
+                final double horz = Math.max(v.getWidth() - x, x);
+                final double vert = Math.max(v.getHeight() - y, y);
+                final float r = (float) Math.hypot(horz, vert);
+                final Animator a
+                        = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
+                a.setDuration(400);
+                a.setInterpolator(mLinearOutSlowIn);
+                a.start();
+
+                mNotificationGutsExposed = guts;
 
                 return true;
             }
@@ -625,9 +667,24 @@
     }
 
     public void dismissPopups() {
-        if (mNotificationBlamePopup != null) {
-            mNotificationBlamePopup.dismiss();
-            mNotificationBlamePopup = null;
+        if (mNotificationGutsExposed != null) {
+            final View v = mNotificationGutsExposed;
+            mNotificationGutsExposed = null;
+
+            final int x = (v.getLeft() + v.getRight()) / 2;
+            final int y = (v.getTop() + v.getBottom()) / 2;
+            final Animator a = ViewAnimationUtils.createCircularReveal(v,
+                    x, y, x, 0);
+            a.setDuration(200);
+            a.setInterpolator(mFastOutLinearIn);
+            a.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    v.setVisibility(View.GONE);
+                }
+            });
+            a.start();
         }
     }
 
@@ -912,6 +969,27 @@
             return inflateViews(entry, parent, true);
     }
 
+    private Drawable loadPackageIconDrawable(String pkg, int userId) {
+        Drawable icon = null;
+        try {
+            icon = mContext.getPackageManager().getApplicationIcon(pkg);
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+
+        return icon;
+    }
+
+    private CharSequence loadPackageName(String pkg) {
+        final PackageManager pm = mContext.getPackageManager();
+        try {
+            ApplicationInfo info = pm.getApplicationInfo(pkg,
+                    PackageManager.GET_UNINSTALLED_PACKAGES);
+            if (info != null) return pm.getApplicationLabel(info);
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+        return pkg;
+    }
+
     private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
         int maxHeight = mRowMaxHeight;
         StatusBarNotification sbn = entry.notification;
@@ -959,8 +1037,15 @@
                     parent, false);
         }
 
-        // for blaming (see SwipeHelper.setLongPressListener)
+        // the notification inspector (see SwipeHelper.setLongPressListener)
         row.setTag(sbn.getPackageName());
+        final View guts = row.findViewById(R.id.notification_guts);
+        final Drawable pkgicon = loadPackageIconDrawable(entry.notification.getPackageName(),
+                entry.notification.getUserId());
+        final String pkgname = loadPackageName(entry.notification.getPackageName()).toString();
+        ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
+        ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(entry.notification.getPostTime());
+        ((TextView) row.findViewById(R.id.pkgname)).setText(pkgname);
 
         workAroundBadLayerDrawableOpacity(row);
         View vetoButton = updateNotificationVetoButton(row, sbn);
@@ -1012,8 +1097,6 @@
             expanded.setExpandedChild(bigContentViewLocal);
         }
 
-        PackageManager pm = mContext.getPackageManager();
-
         // now the public version
         View publicViewLocal = null;
         if (publicNotification != null) {
@@ -1034,6 +1117,9 @@
         }
 
         if (publicViewLocal == null) {
+            PackageManager pm = getPackageManagerForUser(
+                    entry.notification.getUser().getIdentifier());
+
             // Add a basic notification template
             publicViewLocal = LayoutInflater.from(mContext).inflate(
                     com.android.internal.R.layout.notification_template_material_base,
@@ -1153,9 +1239,6 @@
                         // the user switches to home.  We know it is safe to do at this
                         // point, so make sure new activity switches are now allowed.
                         ActivityManagerNative.getDefault().resumeAppSwitches();
-                        // Also, notifications can be launched from the lock screen,
-                        // so dismiss the lock screen when the activity starts.
-                        ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
                     } catch (RemoteException e) {
                     }
 
@@ -1206,6 +1289,9 @@
     protected void visibilityChanged(boolean visible) {
         if (mPanelSlightlyVisible != visible) {
             mPanelSlightlyVisible = visible;
+            if (!visible) {
+                dismissPopups();
+            }
             try {
                 if (visible) {
                     mBarService.onPanelRevealed();
@@ -1335,9 +1421,12 @@
         } else {
             mKeyguardIconOverflowContainer.setVisibility(View.GONE);
         }
-        // Move overflow container to last position.
+        // Move overflow container to second last position.
         mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
-                mStackScroller.getChildCount() - 1);
+                mStackScroller.getChildCount() - 2);
+
+        // Now move dismissView to the last position.
+        mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
     }
 
     private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1670,4 +1759,26 @@
             // Ignore.
         }
     }
+
+    /**
+     * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
+     *         return PackageManager for mContext
+     */
+    protected PackageManager getPackageManagerForUser(int userId) {
+        Context contextForUser = mContext;
+        // UserHandle defines special userId as negative values, e.g. USER_ALL
+        if (userId >= 0) {
+            try {
+                // Create a context for the correct user so if a package isn't installed
+                // for user 0 we can still load information about the package.
+                contextForUser =
+                        mContext.createPackageContextAsUser(mContext.getPackageName(),
+                        Context.CONTEXT_RESTRICTED,
+                        new UserHandle(userId));
+            } catch (NameNotFoundException e) {
+                // Shouldn't fail to find the package name for system ui.
+            }
+        }
+        return contextForUser.getPackageManager();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index eb44002..a82c907 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -54,6 +54,7 @@
     private static final int MSG_SET_WINDOW_STATE           = 13 << MSG_SHIFT;
     private static final int MSG_SHOW_RECENT_APPS           = 14 << MSG_SHIFT;
     private static final int MSG_HIDE_RECENT_APPS           = 15 << MSG_SHIFT;
+    private static final int MSG_BUZZ_BEEP_BLINKED          = 16 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -93,6 +94,7 @@
         public void showSearchPanel();
         public void hideSearchPanel();
         public void setWindowState(int window, int state);
+        public void buzzBeepBlinked();
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -221,6 +223,12 @@
         }
     }
 
+    public void buzzBeepBlinked() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED);
+            mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED);
+        }
+    }
 
     private final class H extends Handler {
         public void handleMessage(Message msg) {
@@ -295,6 +303,9 @@
                 case MSG_SET_WINDOW_STATE:
                     mCallbacks.setWindowState(msg.arg1, msg.arg2);
                     break;
+                case MSG_BUZZ_BEEP_BLINKED:
+                    mCallbacks.buzzBeepBlinked();
+                    break;
 
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
new file mode 100644
index 0000000..d60c17f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.widget.Button;
+import android.widget.TextView;
+import com.android.systemui.R;
+
+public class DismissView extends ExpandableView {
+
+    private Button mClearAllText;
+    private boolean mIsVisible;
+    private boolean mAnimating;
+    private boolean mWillBeGone;
+
+    private final Interpolator mAppearInterpolator = new PathInterpolator(0f, 0.2f, 1f, 1f);
+    private final Interpolator mDisappearInterpolator = new PathInterpolator(0f, 0f, 0.8f, 1f);
+
+    public DismissView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mClearAllText = (Button) findViewById(R.id.dismiss_text);
+        setInvisible();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        setOutlineProvider(null);
+    }
+
+    @Override
+    public boolean isTransparent() {
+        return true;
+    }
+
+    public void performVisibilityAnimation(boolean nowVisible) {
+        animateText(nowVisible, null /* onFinishedRunnable */);
+    }
+
+    public void performVisibilityAnimation(boolean nowVisible, Runnable onFinishedRunnable) {
+        animateText(nowVisible, onFinishedRunnable);
+    }
+
+    public boolean isVisible() {
+        return mIsVisible || mAnimating;
+    }
+
+    /**
+     * Animate the text to a new visibility.
+     *
+     * @param nowVisible should it now be visible
+     * @param onFinishedRunnable A runnable which should be run when the animation is
+     *        finished.
+     */
+    private void animateText(boolean nowVisible, final Runnable onFinishedRunnable) {
+        if (nowVisible != mIsVisible) {
+            // Animate text
+            float endValue = nowVisible ? 1.0f : 0.0f;
+            Interpolator interpolator;
+            if (nowVisible) {
+                interpolator = mAppearInterpolator;
+            } else {
+                interpolator = mDisappearInterpolator;
+            }
+            mAnimating = true;
+            mClearAllText.animate()
+                    .alpha(endValue)
+                    .setInterpolator(interpolator)
+                    .setDuration(260)
+                    .withLayer()
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mAnimating = false;
+                            if (onFinishedRunnable != null) {
+                                onFinishedRunnable.run();
+                            }
+                        }
+                    });
+            mIsVisible = nowVisible;
+        } else {
+            if (onFinishedRunnable != null) {
+                onFinishedRunnable.run();
+            }
+        }
+    }
+
+    public void setInvisible() {
+        mClearAllText.setAlpha(0.0f);
+        mIsVisible = false;
+    }
+
+    @Override
+    public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) {
+        performVisibilityAnimation(false);
+    }
+
+    @Override
+    public void performAddAnimation(long delay) {
+        performVisibilityAnimation(true);
+    }
+
+    @Override
+    public void setScrimAmount(float scrimAmount) {
+        // We don't need to scrim the dismissView
+    }
+
+    public void setOnButtonClickListener(OnClickListener onClickListener) {
+        mClearAllText.setOnClickListener(onClickListener);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    public void cancelAnimation() {
+        mClearAllText.animate().cancel();
+    }
+
+    public boolean willBeGone() {
+        return mWillBeGone;
+    }
+
+    public void setWillBeGone(boolean willBeGone) {
+        mWillBeGone = willBeGone;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 517a4e8..e9989ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.view.MotionEvent;
 import android.view.View;
@@ -46,22 +47,23 @@
     private float mInitialTouchY;
     private boolean mDraggingDown;
     private float mTouchSlop;
-    private OnDragDownListener mOnDragDownListener;
+    private DragDownCallback mDragDownCallback;
     private View mHost;
     private final int[] mTemp2 = new int[2];
     private boolean mDraggedFarEnough;
     private ExpandableView mStartingChild;
     private Interpolator mInterpolator;
+    private float mLastHeight;
 
     public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
-            OnDragDownListener onDragDownListener) {
+            DragDownCallback dragDownCallback) {
         mMinDragDistance = context.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_drag_down_min_distance);
         mInterpolator =
                 AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mCallback = callback;
-        mOnDragDownListener = onDragDownListener;
+        mDragDownCallback = dragDownCallback;
         mHost = host;
     }
 
@@ -86,7 +88,7 @@
                     captureStartingChild(mInitialTouchX, mInitialTouchY);
                     mInitialTouchY = y;
                     mInitialTouchX = x;
-                    mOnDragDownListener.onTouchSlopExceeded();
+                    mDragDownCallback.onTouchSlopExceeded();
                     return true;
                 }
                 break;
@@ -104,29 +106,32 @@
 
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_MOVE:
-                final float h = y - mInitialTouchY;
+                mLastHeight = y - mInitialTouchY;
                 captureStartingChild(mInitialTouchX, mInitialTouchY);
                 if (mStartingChild != null) {
-                    handleExpansion(h, mStartingChild);
+                    handleExpansion(mLastHeight, mStartingChild);
+                } else {
+                    mDragDownCallback.setEmptyDragAmount(mLastHeight);
                 }
-                if (h > mMinDragDistance) {
+                if (mLastHeight > mMinDragDistance) {
                     if (!mDraggedFarEnough) {
                         mDraggedFarEnough = true;
-                        mOnDragDownListener.onThresholdReached();
+                        mDragDownCallback.onThresholdReached();
                     }
                 } else {
                     if (mDraggedFarEnough) {
                         mDraggedFarEnough = false;
-                        mOnDragDownListener.onDragDownReset();
+                        mDragDownCallback.onDragDownReset();
                     }
                 }
                 return true;
             case MotionEvent.ACTION_UP:
-                if (mDraggedFarEnough) {
+                if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild)) {
                     if (mStartingChild != null) {
                         mCallback.setUserLockedChild(mStartingChild, false);
+                    } else {
+                        mDragDownCallback.setEmptyDragAmount(0f);
                     }
-                    mOnDragDownListener.onDraggedDown(mStartingChild);
                     mDraggingDown = false;
                 } else {
                     stopDragging();
@@ -183,12 +188,27 @@
         anim.start();
     }
 
+    private void cancelExpansion() {
+        ValueAnimator anim = ValueAnimator.ofFloat(mLastHeight, 0);
+        anim.setInterpolator(mInterpolator);
+        anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mDragDownCallback.setEmptyDragAmount((Float) animation.getAnimatedValue());
+            }
+        });
+        anim.start();
+    }
+
     private void stopDragging() {
         if (mStartingChild != null) {
             cancelExpansion(mStartingChild);
+        } else {
+            cancelExpansion();
         }
         mDraggingDown = false;
-        mOnDragDownListener.onDragDownReset();
+        mDragDownCallback.onDragDownReset();
     }
 
     private ExpandableView findView(float x, float y) {
@@ -198,10 +218,15 @@
         return mCallback.getChildAtRawPosition(x, y);
     }
 
-    public interface OnDragDownListener {
-        void onDraggedDown(View startingChild);
+    public interface DragDownCallback {
+
+        /**
+         * @return true if the interaction is accepted, false if it should be cancelled
+         */
+        boolean onDraggedDown(View startingChild);
         void onDragDownReset();
         void onThresholdReached();
         void onTouchSlopExceeded();
+        void setEmptyDragAmount(float amount);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index 9968bbc..9f0f84e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.view.ViewPropertyAnimator;
@@ -72,7 +73,7 @@
      * @param endValue the end value of the animator
      * @param velocity the current velocity of the motion
      */
-    public void apply(ValueAnimator animator, float currValue, float endValue, float velocity) {
+    public void apply(Animator animator, float currValue, float endValue, float velocity) {
         apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
     }
 
@@ -101,7 +102,7 @@
      * @param maxDistance the maximum distance for this interaction; the maximum animation length
      *                    gets multiplied by the ratio between the actual distance and this value
      */
-    public void apply(ValueAnimator animator, float currValue, float endValue, float velocity,
+    public void apply(Animator animator, float currValue, float endValue, float velocity,
             float maxDistance) {
         AnimatorProperties properties = getProperties(currValue, endValue, velocity,
                 maxDistance);
@@ -168,7 +169,7 @@
      * @param maxDistance the maximum distance for this interaction; the maximum animation length
      *                    gets multiplied by the ratio between the actual distance and this value
      */
-    public void applyDismissing(ValueAnimator animator, float currValue, float endValue,
+    public void applyDismissing(Animator animator, float currValue, float endValue,
             float velocity, float maxDistance) {
         AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
                 maxDistance);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
new file mode 100644
index 0000000..19bf121
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+import com.android.systemui.R;
+
+/**
+ * An ImageView which does not have overlapping renderings commands and therefore does not need a
+ * layer when alpha is changed.
+ */
+public class KeyguardAffordanceView extends ImageView {
+
+    private static final long CIRCLE_APPEAR_DURATION = 80;
+    private static final long CIRCLE_DISAPPEAR_MAX_DURATION = 200;
+    private static final long NORMAL_ANIMATION_DURATION = 200;
+    public static final float MAX_ICON_SCALE_AMOUNT = 1.5f;
+    public static final float MIN_ICON_SCALE_AMOUNT = 0.8f;
+
+    private final int mMinBackgroundRadius;
+    private final Paint mCirclePaint;
+    private final Interpolator mAppearInterpolator;
+    private final Interpolator mDisappearInterpolator;
+    private final int mInverseColor;
+    private final int mNormalColor;
+    private final ArgbEvaluator mColorInterpolator;
+    private final FlingAnimationUtils mFlingAnimationUtils;
+    private final Drawable mArrowDrawable;
+    private final int mHintChevronPadding;
+    private float mCircleRadius;
+    private int mCenterX;
+    private int mCenterY;
+    private ValueAnimator mCircleAnimator;
+    private ValueAnimator mAlphaAnimator;
+    private ValueAnimator mScaleAnimator;
+    private ValueAnimator mArrowAnimator;
+    private float mCircleStartValue;
+    private boolean mCircleWillBeHidden;
+    private int[] mTempPoint = new int[2];
+    private float mImageScale;
+    private int mCircleColor;
+    private boolean mIsLeft;
+    private float mArrowAlpha = 0.0f;
+    private View mPreviewView;
+    private float mCircleStartRadius;
+    private float mMaxCircleSize;
+    private Animator mPreviewClipper;
+    private AnimatorListenerAdapter mClipEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mPreviewClipper = null;
+        }
+    };
+    private AnimatorListenerAdapter mCircleEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mCircleAnimator = null;
+        }
+    };
+    private AnimatorListenerAdapter mScaleEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mScaleAnimator = null;
+        }
+    };
+    private AnimatorListenerAdapter mAlphaEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mAlphaAnimator = null;
+        }
+    };
+    private AnimatorListenerAdapter mArrowEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mArrowAnimator = null;
+        }
+    };
+
+    public KeyguardAffordanceView(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardAffordanceView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mCirclePaint = new Paint();
+        mCirclePaint.setAntiAlias(true);
+        mCircleColor = 0xffffffff;
+        mCirclePaint.setColor(mCircleColor);
+
+        mNormalColor = 0xffffffff;
+        mInverseColor = 0xff000000;
+        mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
+                R.dimen.keyguard_affordance_min_background_radius);
+        mHintChevronPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.hint_chevron_circle_padding);
+        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.linear_out_slow_in);
+        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.fast_out_linear_in);
+        mColorInterpolator = new ArgbEvaluator();
+        mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f);
+        mArrowDrawable = context.getDrawable(R.drawable.ic_chevron_left);
+        mArrowDrawable.setBounds(0, 0, mArrowDrawable.getIntrinsicWidth(),
+                mArrowDrawable.getIntrinsicHeight());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        mCenterX = getWidth() / 2;
+        mCenterY = getHeight() / 2;
+        mMaxCircleSize = getMaxCircleSize();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        drawBackgroundCircle(canvas);
+        drawArrow(canvas);
+        canvas.save();
+        updateIconColor();
+        canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2);
+        super.onDraw(canvas);
+        canvas.restore();
+    }
+
+    public void setPreviewView(View v) {
+        mPreviewView = v;
+    }
+
+    private void drawArrow(Canvas canvas) {
+        if (mArrowAlpha > 0) {
+            canvas.save();
+            canvas.translate(mCenterX, mCenterY);
+            if (mIsLeft) {
+                canvas.scale(-1.0f, 1.0f);
+            }
+            canvas.translate(- mCircleRadius - mHintChevronPadding
+                    - mArrowDrawable.getIntrinsicWidth() / 2,
+                    - mArrowDrawable.getIntrinsicHeight() / 2);
+            mArrowDrawable.setAlpha((int) (mArrowAlpha * 255));
+            mArrowDrawable.draw(canvas);
+            canvas.restore();
+        }
+    }
+
+    private void updateIconColor() {
+        Drawable drawable = getDrawable().mutate();
+        float alpha = mCircleRadius / mMinBackgroundRadius;
+        alpha = Math.min(1.0f, alpha);
+        int color = (int) mColorInterpolator.evaluate(alpha, mNormalColor, mInverseColor);
+        drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+    }
+
+    private void drawBackgroundCircle(Canvas canvas) {
+        if (mCircleRadius > 0) {
+            updateCircleColor();
+            canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mCirclePaint);
+        }
+    }
+
+    private void updateCircleColor() {
+        float fraction = 0.5f + 0.5f * Math.max(0.0f, Math.min(1.0f,
+                (mCircleRadius - mMinBackgroundRadius) / (0.5f * mMinBackgroundRadius)));
+        if (mPreviewView != null) {
+            float finishingFraction = 1 - Math.max(0, mCircleRadius - mCircleStartRadius)
+                    / (mMaxCircleSize - mCircleStartRadius);
+            fraction *= finishingFraction;
+        }
+        int color = Color.argb((int) (Color.alpha(mCircleColor) * fraction),
+                Color.red(mCircleColor),
+                Color.green(mCircleColor), Color.blue(mCircleColor));
+        mCirclePaint.setColor(color);
+    }
+
+    public void finishAnimation(float velocity, final Runnable mAnimationEndRunnable) {
+        cancelAnimator(mCircleAnimator);
+        cancelAnimator(mPreviewClipper);
+        mCircleStartRadius = mCircleRadius;
+        float maxCircleSize = getMaxCircleSize();
+        ValueAnimator animatorToRadius = getAnimatorToRadius(maxCircleSize);
+        mFlingAnimationUtils.applyDismissing(animatorToRadius, mCircleRadius, maxCircleSize,
+                velocity, maxCircleSize);
+        animatorToRadius.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAnimationEndRunnable.run();
+            }
+        });
+        animatorToRadius.start();
+        setImageAlpha(0, true);
+        if (mPreviewView != null) {
+            mPreviewView.setVisibility(View.VISIBLE);
+            mPreviewClipper = ViewAnimationUtils.createCircularReveal(
+                    mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius,
+                    maxCircleSize);
+            mFlingAnimationUtils.applyDismissing(mPreviewClipper, mCircleRadius, maxCircleSize,
+                    velocity, maxCircleSize);
+            mPreviewClipper.addListener(mClipEndListener);
+            mPreviewClipper.start();
+        }
+    }
+
+    private float getMaxCircleSize() {
+        getLocationInWindow(mTempPoint);
+        float rootWidth = getRootView().getWidth();
+        float width = mTempPoint[0] + mCenterX;
+        width = Math.max(rootWidth - width, width);
+        float height = mTempPoint[1] + mCenterY;
+        return (float) Math.hypot(width, height);
+    }
+
+    public void setCircleRadius(float circleRadius) {
+        setCircleRadius(circleRadius, false);
+    }
+
+    public void setCircleRadiusWithoutAnimation(float circleRadius) {
+        cancelAnimator(mCircleAnimator);
+        setCircleRadius(circleRadius, true);
+    }
+
+    private void setCircleRadius(float circleRadius, boolean noAnimation) {
+
+        // Check if we need a new animation
+        boolean radiusHidden = (mCircleAnimator != null && mCircleWillBeHidden)
+                || (mCircleAnimator == null && mCircleRadius == 0.0f);
+        boolean nowHidden = circleRadius == 0.0f;
+        boolean radiusNeedsAnimation = (radiusHidden != nowHidden) && !noAnimation;
+        if (!radiusNeedsAnimation) {
+            if (mCircleAnimator == null) {
+                mCircleRadius = circleRadius;
+                invalidate();
+                if (nowHidden) {
+                    if (mPreviewView != null) {
+                        mPreviewView.setVisibility(View.INVISIBLE);
+                    }
+                }
+            } else if (!mCircleWillBeHidden) {
+
+                // We just update the end value
+                float diff = circleRadius - mMinBackgroundRadius;
+                PropertyValuesHolder[] values = mCircleAnimator.getValues();
+                values[0].setFloatValues(mCircleStartValue + diff, circleRadius);
+                mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime());
+            }
+        } else {
+            cancelAnimator(mCircleAnimator);
+            cancelAnimator(mPreviewClipper);
+            ValueAnimator animator = getAnimatorToRadius(circleRadius);
+            Interpolator interpolator = circleRadius == 0.0f
+                    ? mDisappearInterpolator
+                    : mAppearInterpolator;
+            animator.setInterpolator(interpolator);
+            float durationFactor = Math.abs(mCircleRadius - circleRadius)
+                    / (float) mMinBackgroundRadius;
+            long duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor);
+            duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION);
+            animator.setDuration(duration);
+            animator.start();
+            if (mPreviewView != null) {
+                mPreviewView.setVisibility(View.VISIBLE);
+                mPreviewClipper = ViewAnimationUtils.createCircularReveal(
+                        mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius,
+                        circleRadius);
+                mPreviewClipper.setInterpolator(interpolator);
+                mPreviewClipper.setDuration(duration);
+                mPreviewClipper.addListener(mClipEndListener);
+                mPreviewClipper.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mPreviewView.setVisibility(View.INVISIBLE);
+                    }
+                });
+                mPreviewClipper.start();
+            }
+        }
+    }
+
+    private ValueAnimator getAnimatorToRadius(float circleRadius) {
+        ValueAnimator animator = ValueAnimator.ofFloat(mCircleRadius, circleRadius);
+        mCircleAnimator = animator;
+        mCircleStartValue = mCircleRadius;
+        mCircleWillBeHidden = circleRadius == 0.0f;
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mCircleRadius = (float) animation.getAnimatedValue();
+                invalidate();
+            }
+        });
+        animator.addListener(mCircleEndListener);
+        return animator;
+    }
+
+    private void cancelAnimator(Animator animator) {
+        if (animator != null) {
+            animator.cancel();
+        }
+    }
+
+    public void setImageScale(float imageScale, boolean animate) {
+        setImageScale(imageScale, animate, -1, null);
+    }
+
+    /**
+     * Sets the scale of the containing image
+     *
+     * @param imageScale The new Scale.
+     * @param animate Should an animation be performed
+     * @param duration If animate, whats the duration? When -1 we take the default duration
+     * @param interpolator If animate, whats the interpolator? When null we take the default
+     *                     interpolator.
+     */
+    public void setImageScale(float imageScale, boolean animate, long duration,
+            Interpolator interpolator) {
+        cancelAnimator(mScaleAnimator);
+        if (!animate) {
+            mImageScale = imageScale;
+            invalidate();
+        } else {
+            ValueAnimator animator = ValueAnimator.ofFloat(mImageScale, imageScale);
+            mScaleAnimator = animator;
+            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    mImageScale = (float) animation.getAnimatedValue();
+                    invalidate();
+                }
+            });
+            animator.addListener(mScaleEndListener);
+            if (interpolator == null) {
+                interpolator = imageScale == 0.0f
+                        ? mDisappearInterpolator
+                        : mAppearInterpolator;
+            }
+            animator.setInterpolator(interpolator);
+            if (duration == -1) {
+                float durationFactor = Math.abs(mImageScale - imageScale)
+                        / (1.0f - MIN_ICON_SCALE_AMOUNT);
+                durationFactor = Math.min(1.0f, durationFactor);
+                duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
+            }
+            animator.setDuration(duration);
+            animator.start();
+        }
+    }
+
+    public void setImageAlpha(float alpha, boolean animate) {
+        setImageAlpha(alpha, animate, -1, null, null);
+    }
+
+    /**
+     * Sets the alpha of the containing image
+     *
+     * @param alpha The new alpha.
+     * @param animate Should an animation be performed
+     * @param duration If animate, whats the duration? When -1 we take the default duration
+     * @param interpolator If animate, whats the interpolator? When null we take the default
+     *                     interpolator.
+     */
+    public void setImageAlpha(float alpha, boolean animate, long duration,
+            Interpolator interpolator, Runnable runnable) {
+        cancelAnimator(mAlphaAnimator);
+        int endAlpha = (int) (alpha * 255);
+        if (!animate) {
+            setImageAlpha(endAlpha);
+        } else {
+            int currentAlpha = getImageAlpha();
+            ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha);
+            mAlphaAnimator = animator;
+            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    setImageAlpha((int) animation.getAnimatedValue());
+                }
+            });
+            animator.addListener(mAlphaEndListener);
+            if (interpolator == null) {
+                interpolator = alpha == 0.0f
+                        ? mDisappearInterpolator
+                        : mAppearInterpolator;
+            }
+            animator.setInterpolator(interpolator);
+            if (duration == -1) {
+                float durationFactor = Math.abs(currentAlpha - endAlpha) / 255f;
+                durationFactor = Math.min(1.0f, durationFactor);
+                duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
+            }
+            animator.setDuration(duration);
+            if (runnable != null) {
+                animator.addListener(getEndListener(runnable));
+            }
+            animator.start();
+        }
+    }
+
+    private Animator.AnimatorListener getEndListener(final Runnable runnable) {
+        return new AnimatorListenerAdapter() {
+            boolean mCancelled;
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!mCancelled) {
+                    runnable.run();
+                }
+            }
+        };
+    }
+
+    public float getCircleRadius() {
+        return mCircleRadius;
+    }
+
+    public void showArrow(boolean show) {
+        cancelAnimator(mArrowAnimator);
+        float targetAlpha = show ? 1.0f : 0.0f;
+        if (mArrowAlpha == targetAlpha) {
+            return;
+        }
+        ValueAnimator animator = ValueAnimator.ofFloat(mArrowAlpha, targetAlpha);
+        mArrowAnimator = animator;
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mArrowAlpha = (float) animation.getAnimatedValue();
+                invalidate();
+            }
+        });
+        animator.addListener(mArrowEndListener);
+        Interpolator interpolator = show
+                    ? mAppearInterpolator
+                    : mDisappearInterpolator;
+        animator.setInterpolator(interpolator);
+        float durationFactor = Math.abs(mArrowAlpha - targetAlpha);
+        long duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
+        animator.setDuration(duration);
+        animator.start();
+    }
+
+    public void setIsLeft(boolean left) {
+        mIsLeft = left;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
index ce5ab5a..c75bd28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
@@ -65,13 +65,7 @@
     }
 
     private void applyColor(Notification notification, StatusBarIconView view) {
-        if (notification.color == Notification.COLOR_DEFAULT) {
-            if (mNotificationColorUtil.isGrayscale(view.getDrawable())) {
-                view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
-            }
-        } else {
-            view.setColorFilter(notification.color, PorterDuff.Mode.SRC_ATOP);
-        }
+        view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
     }
 
     private void updateMoreText() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index f5d4889..8bae19a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -167,6 +167,11 @@
         apply();
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     private void applyInetProblem(ImageView iv) {
         iv.setColorFilter(Build.IS_DEBUGGABLE && mInetProblem ? PROBLEM_FILTER : null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
new file mode 100644
index 0000000..9cc559f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
+
+/**
+ * A touch handler of the keyguard which is responsible for launching phone and camera affordances.
+ */
+public class KeyguardAffordanceHelper {
+
+    public static final float SWIPE_RESTING_ALPHA_AMOUNT = 0.5f;
+    public static final long HINT_PHASE1_DURATION = 200;
+    private static final long HINT_PHASE2_DURATION = 350;
+    private static final float BACKGROUND_RADIUS_SCALE_FACTOR = 0.15f;
+    private static final int HINT_CIRCLE_OPEN_DURATION = 500;
+
+    private final Context mContext;
+
+    private FlingAnimationUtils mFlingAnimationUtils;
+    private Callback mCallback;
+    private int mTrackingPointer;
+    private VelocityTracker mVelocityTracker;
+    private boolean mSwipingInProgress;
+    private float mInitialTouchX;
+    private float mInitialTouchY;
+    private float mTranslation;
+    private float mTranslationOnDown;
+    private int mTouchSlop;
+    private int mMinTranslationAmount;
+    private int mMinFlingVelocity;
+    private int mHintGrowAmount;
+    private final KeyguardAffordanceView mLeftIcon;
+    private final KeyguardAffordanceView mCenterIcon;
+    private final KeyguardAffordanceView mRightIcon;
+    private Interpolator mAppearInterpolator;
+    private Interpolator mDisappearInterpolator;
+    private Animator mSwipeAnimator;
+    private int mMinBackgroundRadius;
+    private boolean mMotionPerformedByUser;
+    private AnimatorListenerAdapter mFlingEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mSwipeAnimator = null;
+            setSwipingInProgress(false);
+        }
+    };
+    private Runnable mAnimationEndRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mCallback.onAnimationToSideEnded();
+        }
+    };
+
+    KeyguardAffordanceHelper(Callback callback, Context context) {
+        mContext = context;
+        mCallback = callback;
+        mLeftIcon = mCallback.getLeftIcon();
+        mLeftIcon.setIsLeft(true);
+        mCenterIcon = mCallback.getCenterIcon();
+        mRightIcon = mCallback.getRightIcon();
+        mLeftIcon.setPreviewView(mCallback.getLeftPreview());
+        mRightIcon.setPreviewView(mCallback.getRightPreview());
+        updateIcon(mLeftIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
+        updateIcon(mCenterIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
+        updateIcon(mRightIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
+        initDimens();
+    }
+
+    private void initDimens() {
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
+        mMinTranslationAmount = mContext.getResources().getDimensionPixelSize(
+                R.dimen.keyguard_min_swipe_amount);
+        mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
+                R.dimen.keyguard_affordance_min_background_radius);
+        mHintGrowAmount =
+                mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways);
+        mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
+        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.linear_out_slow_in);
+        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.fast_out_linear_in);
+    }
+
+    public boolean onTouchEvent(MotionEvent event) {
+        int pointerIndex = event.findPointerIndex(mTrackingPointer);
+        if (pointerIndex < 0) {
+            pointerIndex = 0;
+            mTrackingPointer = event.getPointerId(pointerIndex);
+        }
+        final float y = event.getY(pointerIndex);
+        final float x = event.getX(pointerIndex);
+
+        boolean isUp = false;
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                if (mSwipingInProgress) {
+                    cancelAnimation();
+                }
+                mInitialTouchY = y;
+                mInitialTouchX = x;
+                mTranslationOnDown = mTranslation;
+                initVelocityTracker();
+                trackMovement(event);
+                mMotionPerformedByUser = false;
+                break;
+
+            case MotionEvent.ACTION_POINTER_UP:
+                final int upPointer = event.getPointerId(event.getActionIndex());
+                if (mTrackingPointer == upPointer) {
+                    // gesture is ongoing, find a new pointer to track
+                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                    final float newY = event.getY(newIndex);
+                    final float newX = event.getX(newIndex);
+                    mTrackingPointer = event.getPointerId(newIndex);
+                    mInitialTouchY = newY;
+                    mInitialTouchX = newX;
+                    mTranslationOnDown = mTranslation;
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final float w = x - mInitialTouchX;
+                trackMovement(event);
+                if (((leftSwipePossible() && w > mTouchSlop)
+                        || (rightSwipePossible() && w < -mTouchSlop))
+                        && Math.abs(w) > Math.abs(y - mInitialTouchY)
+                        && !mSwipingInProgress) {
+                    cancelAnimation();
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    mTranslationOnDown = mTranslation;
+                    setSwipingInProgress(true);
+                }
+                if (mSwipingInProgress) {
+                    setTranslation(mTranslationOnDown + x - mInitialTouchX, false, false);
+                }
+                break;
+
+            case MotionEvent.ACTION_UP:
+                isUp = true;
+            case MotionEvent.ACTION_CANCEL:
+                mTrackingPointer = -1;
+                trackMovement(event);
+                if (mSwipingInProgress) {
+                    flingWithCurrentVelocity(!isUp);
+                }
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.recycle();
+                    mVelocityTracker = null;
+                }
+                break;
+        }
+        return true;
+    }
+
+    private void setSwipingInProgress(boolean inProgress) {
+        mSwipingInProgress = inProgress;
+        if (inProgress) {
+            mCallback.onSwipingStarted();
+        }
+    }
+
+    private boolean rightSwipePossible() {
+        return mRightIcon.getVisibility() == View.VISIBLE;
+    }
+
+    private boolean leftSwipePossible() {
+        return mLeftIcon.getVisibility() == View.VISIBLE;
+    }
+
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return false;
+    }
+
+    public void startHintAnimation(boolean right, Runnable onFinishedListener) {
+
+        startHintAnimationPhase1(right, onFinishedListener);
+    }
+
+    private void startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener) {
+        final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
+        targetView.showArrow(true);
+        ValueAnimator animator = getAnimatorToRadius(right, mHintGrowAmount);
+        animator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCancelled;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mCancelled) {
+                    mSwipeAnimator = null;
+                    onFinishedListener.run();
+                    targetView.showArrow(false);
+                } else {
+                    startUnlockHintAnimationPhase2(right, onFinishedListener);
+                }
+            }
+        });
+        animator.setInterpolator(mAppearInterpolator);
+        animator.setDuration(HINT_PHASE1_DURATION);
+        animator.start();
+        mSwipeAnimator = animator;
+    }
+
+    /**
+     * Phase 2: Move back.
+     */
+    private void startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener) {
+        final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
+        ValueAnimator animator = getAnimatorToRadius(right, 0);
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mSwipeAnimator = null;
+                targetView.showArrow(false);
+                onFinishedListener.run();
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                targetView.showArrow(false);
+            }
+        });
+        animator.setInterpolator(mDisappearInterpolator);
+        animator.setDuration(HINT_PHASE2_DURATION);
+        animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION);
+        animator.start();
+        mSwipeAnimator = animator;
+    }
+
+    private ValueAnimator getAnimatorToRadius(final boolean right, int radius) {
+        final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
+        ValueAnimator animator = ValueAnimator.ofFloat(targetView.getCircleRadius(), radius);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float newRadius = (float) animation.getAnimatedValue();
+                targetView.setCircleRadiusWithoutAnimation(newRadius);
+                float translation = getTranslationFromRadius(newRadius);
+                mTranslation = right ? -translation : translation;
+                updateIconsFromRadius(targetView, newRadius);
+            }
+        });
+        return animator;
+    }
+
+    private void cancelAnimation() {
+        if (mSwipeAnimator != null) {
+            mSwipeAnimator.cancel();
+        }
+    }
+
+    private void flingWithCurrentVelocity(boolean forceSnapBack) {
+        float vel = getCurrentVelocity();
+
+        // We snap back if the current translation is not far enough
+        boolean snapBack = Math.abs(mTranslation) < Math.abs(mTranslationOnDown)
+                + mMinTranslationAmount;
+
+        // or if the velocity is in the opposite direction.
+        boolean velIsInWrongDirection = vel * mTranslation < 0;
+        snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection;
+        vel = snapBack ^ velIsInWrongDirection ? 0 : vel;
+        fling(vel, snapBack || forceSnapBack);
+    }
+
+    private void fling(float vel, final boolean snapBack) {
+        float target = mTranslation < 0 ? -mCallback.getPageWidth() : mCallback.getPageWidth();
+        target = snapBack ? 0 : target;
+
+        ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target);
+        mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mTranslation = (float) animation.getAnimatedValue();
+            }
+        });
+        animator.addListener(mFlingEndListener);
+        if (!snapBack) {
+            startFinishingCircleAnimation(vel * 0.375f, mAnimationEndRunnable);
+            mCallback.onAnimationToSideStarted(mTranslation < 0);
+        } else {
+            reset(true);
+        }
+        animator.start();
+        mSwipeAnimator = animator;
+    }
+
+    private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable) {
+        KeyguardAffordanceView targetView = mTranslation > 0 ? mLeftIcon : mRightIcon;
+        targetView.finishAnimation(velocity, mAnimationEndRunnable);
+    }
+
+    private void setTranslation(float translation, boolean isReset, boolean animateReset) {
+        translation = rightSwipePossible() ? translation : Math.max(0, translation);
+        translation = leftSwipePossible() ? translation : Math.min(0, translation);
+        float absTranslation = Math.abs(translation);
+        if (absTranslation > Math.abs(mTranslationOnDown) + mMinTranslationAmount ||
+                mMotionPerformedByUser) {
+            mMotionPerformedByUser = true;
+        }
+        if (translation != mTranslation || isReset) {
+            KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
+            KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
+            float alpha = absTranslation / mMinTranslationAmount;
+
+            // We interpolate the alpha of the other icons to 0
+            float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
+            fadeOutAlpha = Math.max(0.0f, fadeOutAlpha);
+
+            // We interpolate the alpha of the targetView to 1
+            alpha = fadeOutAlpha + alpha;
+
+            boolean animateIcons = isReset && animateReset;
+            float radius = getRadiusFromTranslation(absTranslation);
+            if (!isReset) {
+                updateIcon(targetView, radius, alpha, false);
+            } else {
+                updateIcon(targetView, 0.0f, fadeOutAlpha, animateIcons);
+            }
+            updateIcon(otherView, 0.0f, fadeOutAlpha, animateIcons);
+            updateIcon(mCenterIcon, 0.0f, fadeOutAlpha, animateIcons);
+
+            mTranslation = translation;
+        }
+    }
+
+    private void updateIconsFromRadius(KeyguardAffordanceView targetView, float newRadius) {
+        float alpha = newRadius / mMinBackgroundRadius;
+
+        // We interpolate the alpha of the other icons to 0
+        float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
+        fadeOutAlpha = Math.max(0.0f, fadeOutAlpha);
+
+        // We interpolate the alpha of the targetView to 1
+        alpha = fadeOutAlpha + alpha;
+        KeyguardAffordanceView otherView = targetView == mRightIcon ? mLeftIcon : mRightIcon;
+        updateIconAlpha(targetView, alpha, false);
+        updateIconAlpha(otherView, fadeOutAlpha, false);
+        updateIconAlpha(mCenterIcon, fadeOutAlpha, false);
+    }
+
+    private float getTranslationFromRadius(float circleSize) {
+        float translation = (circleSize - mMinBackgroundRadius) / BACKGROUND_RADIUS_SCALE_FACTOR;
+        return Math.max(0, translation);
+    }
+
+    private float getRadiusFromTranslation(float translation) {
+        return translation * BACKGROUND_RADIUS_SCALE_FACTOR + mMinBackgroundRadius;
+    }
+
+    public void animateHideLeftRightIcon() {
+        updateIcon(mRightIcon, 0f, 0f, true);
+        updateIcon(mLeftIcon, 0f, 0f, true);
+    }
+
+    private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha,
+            boolean animate) {
+        if (view.getVisibility() != View.VISIBLE) {
+            return;
+        }
+        view.setCircleRadius(circleRadius);
+        updateIconAlpha(view, alpha, animate);
+    }
+
+    private void updateIconAlpha(KeyguardAffordanceView view, float alpha, boolean animate) {
+        float scale = getScale(alpha);
+        alpha = Math.min(1.0f, alpha);
+        view.setImageAlpha(alpha, animate);
+        view.setImageScale(scale, animate);
+    }
+
+    private float getScale(float alpha) {
+        float scale = alpha / SWIPE_RESTING_ALPHA_AMOUNT * 0.2f +
+                KeyguardAffordanceView.MIN_ICON_SCALE_AMOUNT;
+        return Math.min(scale, KeyguardAffordanceView.MAX_ICON_SCALE_AMOUNT);
+    }
+
+    private void trackMovement(MotionEvent event) {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.addMovement(event);
+        }
+    }
+
+    private void initVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+        }
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    private float getCurrentVelocity() {
+        if (mVelocityTracker == null) {
+            return 0;
+        }
+        mVelocityTracker.computeCurrentVelocity(1000);
+        return mVelocityTracker.getXVelocity();
+    }
+
+    public void onConfigurationChanged() {
+        initDimens();
+    }
+
+    public void reset(boolean animate) {
+        if (mSwipeAnimator != null) {
+            mSwipeAnimator.cancel();
+        }
+        setTranslation(0.0f, true, animate);
+        setSwipingInProgress(false);
+    }
+
+    public interface Callback {
+
+        /**
+         * Notifies the callback when an animation to a side page was started.
+         *
+         * @param rightPage Is the page animated to the right page?
+         */
+        void onAnimationToSideStarted(boolean rightPage);
+
+        /**
+         * Notifies the callback the animation to a side page has ended.
+         */
+        void onAnimationToSideEnded();
+
+        float getPageWidth();
+
+        void onSwipingStarted();
+
+        KeyguardAffordanceView getLeftIcon();
+
+        KeyguardAffordanceView getCenterIcon();
+
+        KeyguardAffordanceView getRightIcon();
+
+        View getLeftPreview();
+
+        View getRightPreview();
+    }
+}
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 74bc698..b5f517d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -30,6 +30,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -39,6 +40,8 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.systemui.statusbar.policy.PreviewInflater;
 
 /**
  * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
@@ -56,10 +59,14 @@
             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
     private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
 
-    private ImageView mCameraImageView;
-    private ImageView mPhoneImageView;
-    private ImageView mLockIcon;
+    private KeyguardAffordanceView mCameraImageView;
+    private KeyguardAffordanceView mPhoneImageView;
+    private KeyguardAffordanceView mLockIcon;
     private View mIndicationText;
+    private ViewGroup mPreviewContainer;
+
+    private View mPhonePreview;
+    private View mCameraPreview;
 
     private ActivityStarter mActivityStarter;
     private UnlockMethodCache mUnlockMethodCache;
@@ -87,9 +94,10 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mLockPatternUtils = new LockPatternUtils(mContext);
-        mCameraImageView = (ImageView) findViewById(R.id.camera_button);
-        mPhoneImageView = (ImageView) findViewById(R.id.phone_button);
-        mLockIcon = (ImageView) findViewById(R.id.lock_icon);
+        mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
+        mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
+        mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button);
+        mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         watchForCameraPolicyChanges();
         watchForAccessibilityChanges();
@@ -98,6 +106,9 @@
         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
         mUnlockMethodCache.addListener(this);
         updateTrust();
+        setClipChildren(false);
+        setClipToPadding(false);
+        inflatePreviews();
     }
 
     public void setActivityStarter(ActivityStarter activityStarter) {
@@ -228,15 +239,23 @@
         mLockIcon.setImageResource(iconRes);
     }
 
-    public ImageView getPhoneImageView() {
+    public KeyguardAffordanceView getPhoneView() {
         return mPhoneImageView;
     }
 
-    public ImageView getCameraImageView() {
+    public KeyguardAffordanceView getCameraView() {
         return mCameraImageView;
     }
 
-    public ImageView getLockIcon() {
+    public View getPhonePreview() {
+        return mPhonePreview;
+    }
+
+    public View getCameraPreview() {
+        return mCameraPreview;
+    }
+
+    public KeyguardAffordanceView getLockIcon() {
         return mLockIcon;
     }
 
@@ -255,6 +274,20 @@
         updateCameraVisibility();
     }
 
+    private void inflatePreviews() {
+        PreviewInflater inflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
+        mPhonePreview = inflater.inflatePreview(PHONE_INTENT);
+        mCameraPreview = inflater.inflatePreview(getCameraIntent());
+        if (mPhonePreview != null) {
+            mPreviewContainer.addView(mPhonePreview);
+            mPhonePreview.setVisibility(View.INVISIBLE);
+        }
+        if (mCameraPreview != null) {
+            mPreviewContainer.addView(mCameraPreview);
+            mCameraPreview.setVisibility(View.INVISIBLE);
+        }
+    }
+
     private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             post(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 3aaace4..e6ffde0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -100,7 +100,7 @@
                     .withLayer()
 
                     // Make it disappear faster, as the focus should be on the activity behind.
-                    .setDuration(duration / 3)
+                    .setDuration(duration / 2)
                     .setInterpolator(mFadeOutInterpolator)
                     .setStartDelay(delay)
                     .withEndAction(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 319096d..a15d35e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -36,7 +36,6 @@
     private static final float CLOCK_SCALE_FADE_END = 0.75f;
     private static final float CLOCK_SCALE_FADE_END_NO_NOTIFS = 0.5f;
 
-
     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f;
     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f;
 
@@ -50,6 +49,8 @@
     private int mNotificationCount;
     private int mHeight;
     private int mKeyguardStatusHeight;
+    private float mEmptyDragAmount;
+    private float mDensity;
 
     /**
      * The number (fractional) of notifications the "more" card counts when calculating how many
@@ -81,16 +82,18 @@
         mMoreCardNotificationAmount =
                 (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) /
                         res.getDimensionPixelSize(R.dimen.notification_min_height);
+        mDensity = res.getDisplayMetrics().density;
     }
 
     public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
-            int notificationCount, int height, int keyguardStatusHeight) {
+            int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount) {
         mMaxKeyguardNotifications = maxKeyguardNotifications;
         mMaxPanelHeight = maxPanelHeight;
         mExpandedHeight = expandedHeight;
         mNotificationCount = notificationCount;
         mHeight = height;
         mKeyguardStatusHeight = keyguardStatusHeight;
+        mEmptyDragAmount = emptyDragAmount;
     }
 
     public void run(Result result) {
@@ -116,6 +119,7 @@
         float progress = distanceToScaleEnd / (startPadding - scaleEnd);
         progress = Math.max(0.0f, Math.min(progress, 1.0f));
         progress = mAccelerateInterpolator.getInterpolation(progress);
+        progress *= Math.pow(1 + mEmptyDragAmount / mDensity / 300, 0.3f);
         return progress;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
deleted file mode 100644
index d5f9619..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.os.PowerManager;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.FlingAnimationUtils;
-
-import java.util.ArrayList;
-
-/**
- * A touch handler of the Keyguard which is responsible for swiping the content left or right.
- */
-public class KeyguardPageSwipeHelper {
-
-    private static final float SWIPE_MAX_ICON_SCALE_AMOUNT = 2.0f;
-    public static final float SWIPE_RESTING_ALPHA_AMOUNT = 0.5f;
-    public static final long HINT_PHASE1_DURATION = 250;
-    private static final long HINT_PHASE2_DURATION = 450;
-
-    private final Context mContext;
-
-    private FlingAnimationUtils mFlingAnimationUtils;
-    private Callback mCallback;
-    private int mTrackingPointer;
-    private VelocityTracker mVelocityTracker;
-    private boolean mSwipingInProgress;
-    private float mInitialTouchX;
-    private float mInitialTouchY;
-    private float mTranslation;
-    private float mTranslationOnDown;
-    private int mTouchSlop;
-    private int mMinTranslationAmount;
-    private int mMinFlingVelocity;
-    private int mHintDistance;
-    private final View mLeftIcon;
-    private final View mCenterIcon;
-    private final View mRightIcon;
-    private Interpolator mFastOutSlowIn;
-    private Interpolator mBounceInterpolator;
-    private Animator mSwipeAnimator;
-    private boolean mCallbackCalled;
-
-    KeyguardPageSwipeHelper(Callback callback, Context context) {
-        mContext = context;
-        mCallback = callback;
-        mLeftIcon = mCallback.getLeftIcon();
-        mCenterIcon = mCallback.getCenterIcon();
-        mRightIcon = mCallback.getRightIcon();
-        updateIcon(mLeftIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
-        updateIcon(mCenterIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
-        updateIcon(mRightIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
-        initDimens();
-    }
-
-    private void initDimens() {
-        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
-        mTouchSlop = configuration.getScaledTouchSlop();
-        mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
-        mMinTranslationAmount = mContext.getResources().getDimensionPixelSize(
-                R.dimen.keyguard_min_swipe_amount);
-        mHintDistance =
-                mContext.getResources().getDimensionPixelSize(R.dimen.hint_move_distance_sideways);
-        mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
-        mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_slow_in);
-        mBounceInterpolator = new BounceInterpolator();
-    }
-
-    public boolean onTouchEvent(MotionEvent event) {
-        int pointerIndex = event.findPointerIndex(mTrackingPointer);
-        if (pointerIndex < 0) {
-            pointerIndex = 0;
-            mTrackingPointer = event.getPointerId(pointerIndex);
-        }
-        final float y = event.getY(pointerIndex);
-        final float x = event.getX(pointerIndex);
-
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                if (mSwipingInProgress) {
-                    cancelAnimations();
-                }
-                mInitialTouchY = y;
-                mInitialTouchX = x;
-                mTranslationOnDown = mTranslation;
-                initVelocityTracker();
-                trackMovement(event);
-                break;
-
-            case MotionEvent.ACTION_POINTER_UP:
-                final int upPointer = event.getPointerId(event.getActionIndex());
-                if (mTrackingPointer == upPointer) {
-                    // gesture is ongoing, find a new pointer to track
-                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
-                    final float newY = event.getY(newIndex);
-                    final float newX = event.getX(newIndex);
-                    mTrackingPointer = event.getPointerId(newIndex);
-                    mInitialTouchY = newY;
-                    mInitialTouchX = newX;
-                    mTranslationOnDown = mTranslation;
-                }
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                final float w = x - mInitialTouchX;
-                trackMovement(event);
-                if (((leftSwipePossible() && w > mTouchSlop)
-                        || (rightSwipePossible() && w < -mTouchSlop))
-                        && Math.abs(w) > Math.abs(y - mInitialTouchY)
-                        && !mSwipingInProgress) {
-                    cancelAnimations();
-                    mInitialTouchY = y;
-                    mInitialTouchX = x;
-                    mTranslationOnDown = mTranslation;
-                    mSwipingInProgress = true;
-                }
-                if (mSwipingInProgress) {
-                    setTranslation(mTranslationOnDown + x - mInitialTouchX, false);
-                }
-                break;
-
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mTrackingPointer = -1;
-                trackMovement(event);
-                if (mSwipingInProgress) {
-                    flingWithCurrentVelocity();
-                }
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.recycle();
-                    mVelocityTracker = null;
-                }
-                break;
-        }
-        return true;
-    }
-
-    private boolean rightSwipePossible() {
-        return mRightIcon.getVisibility() == View.VISIBLE;
-    }
-
-    private boolean leftSwipePossible() {
-        return mLeftIcon.getVisibility() == View.VISIBLE;
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return false;
-    }
-
-    public void startHintAnimation(boolean right, Runnable onFinishedListener) {
-        startHintAnimationPhase1(right, onFinishedListener);
-    }
-
-    /**
-     * Phase 1: Move everything sidewards.
-     */
-    private void startHintAnimationPhase1(boolean right, final Runnable onFinishedListener) {
-        float target = right ? -mHintDistance : mHintDistance;
-        startHintTranslationAnimations(target, HINT_PHASE1_DURATION, mFastOutSlowIn);
-        ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target);
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                mTranslation = (float) animation.getAnimatedValue();
-            }
-        });
-        animator.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (mCancelled) {
-                    mSwipeAnimator = null;
-                    onFinishedListener.run();
-                } else {
-                    startUnlockHintAnimationPhase2(onFinishedListener);
-                }
-            }
-        });
-        animator.setInterpolator(mFastOutSlowIn);
-        animator.setDuration(HINT_PHASE1_DURATION);
-        animator.start();
-        mSwipeAnimator = animator;
-    }
-
-    /**
-     * Phase 2: Move back.
-     */
-    private void startUnlockHintAnimationPhase2(final Runnable onFinishedListener) {
-        startHintTranslationAnimations(0f /* target */, HINT_PHASE2_DURATION, mBounceInterpolator);
-        ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, 0f);
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                mTranslation = (float) animation.getAnimatedValue();
-            }
-        });
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mSwipeAnimator = null;
-                onFinishedListener.run();
-            }
-        });
-        animator.setInterpolator(mBounceInterpolator);
-        animator.setDuration(HINT_PHASE2_DURATION);
-        animator.start();
-        mSwipeAnimator = animator;
-    }
-
-    private void startHintTranslationAnimations(float target, long duration,
-            Interpolator interpolator) {
-        ArrayList<View> targetViews = mCallback.getTranslationViews();
-        for (View targetView : targetViews) {
-            targetView.animate()
-                    .setDuration(duration)
-                    .setInterpolator(interpolator)
-                    .translationX(target);
-        }
-    }
-
-    private void cancelAnimations() {
-        ArrayList<View> targetViews = mCallback.getTranslationViews();
-        for (View target : targetViews) {
-            target.animate().cancel();
-        }
-        View targetView = mTranslation > 0 ? mLeftIcon : mRightIcon;
-        targetView.animate().cancel();
-        if (mSwipeAnimator != null) {
-            mSwipeAnimator.cancel();
-            hideInactiveIcons(true);
-        }
-    }
-
-    private void flingWithCurrentVelocity() {
-        float vel = getCurrentVelocity();
-
-        // We snap back if the current translation is not far enough
-        boolean snapBack = Math.abs(mTranslation) < mMinTranslationAmount;
-
-        // or if the velocity is in the opposite direction.
-        boolean velIsInWrongDirection = vel * mTranslation < 0;
-        snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection;
-        vel = snapBack ^ velIsInWrongDirection ? 0 : vel;
-        fling(vel, snapBack);
-    }
-
-    private void fling(float vel, final boolean snapBack) {
-        float target = mTranslation < 0 ? -mCallback.getPageWidth() : mCallback.getPageWidth();
-        target = snapBack ? 0 : target;
-
-        // translation Animation
-        startTranslationAnimations(vel, target);
-
-        // animate left / right icon
-        startIconAnimation(vel, snapBack, target);
-
-        ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target);
-        mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                mTranslation = (float) animation.getAnimatedValue();
-            }
-        });
-        animator.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mSwipeAnimator = null;
-                mSwipingInProgress = false;
-                if (!snapBack && !mCallbackCalled && !mCancelled) {
-
-                    // ensure that the callback is called eventually
-                    mCallback.onAnimationToSideStarted(mTranslation < 0);
-                    mCallbackCalled = true;
-                }
-            }
-        });
-        if (!snapBack) {
-            mCallbackCalled = false;
-            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                int frameNumber;
-
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    if (frameNumber == 2 && !mCallbackCalled) {
-
-                        // we have to wait for the second frame for this call,
-                        // until the render thread has definitely kicked in, to avoid a lag.
-                        mCallback.onAnimationToSideStarted(mTranslation < 0);
-                        mCallbackCalled = true;
-                    }
-                    frameNumber++;
-                }
-            });
-        } else {
-            showAllIcons(true);
-        }
-        animator.start();
-        mSwipeAnimator = animator;
-    }
-
-    private void startTranslationAnimations(float vel, float target) {
-        ArrayList<View> targetViews = mCallback.getTranslationViews();
-        for (View targetView : targetViews) {
-            ViewPropertyAnimator animator = targetView.animate();
-            mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
-            animator.translationX(target);
-        }
-    }
-
-    private void startIconAnimation(float vel, boolean snapBack, float target) {
-        float scale = snapBack ? 1.0f : SWIPE_MAX_ICON_SCALE_AMOUNT;
-        float alpha = snapBack ? SWIPE_RESTING_ALPHA_AMOUNT : 1.0f;
-        View targetView = mTranslation > 0
-                ? mLeftIcon
-                : mRightIcon;
-        if (targetView.getVisibility() == View.VISIBLE) {
-            ViewPropertyAnimator iconAnimator = targetView.animate();
-            mFlingAnimationUtils.apply(iconAnimator, mTranslation, target, vel);
-            iconAnimator.scaleX(scale);
-            iconAnimator.scaleY(scale);
-            iconAnimator.alpha(alpha);
-        }
-    }
-
-    private void setTranslation(float translation, boolean isReset) {
-        translation = rightSwipePossible() ? translation : Math.max(0, translation);
-        translation = leftSwipePossible() ? translation : Math.min(0, translation);
-        if (translation != mTranslation || isReset) {
-            ArrayList<View> translatedViews = mCallback.getTranslationViews();
-            for (View view : translatedViews) {
-                view.setTranslationX(translation);
-            }
-            if (translation == 0.0f) {
-                boolean animate = !isReset;
-                showAllIcons(animate);
-            } else {
-                View targetView = translation > 0 ? mLeftIcon : mRightIcon;
-                float progress = Math.abs(translation) / mCallback.getPageWidth();
-                progress = Math.min(progress, 1.0f);
-                float alpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - progress) + progress;
-                float scale = (1.0f - progress) + progress * SWIPE_MAX_ICON_SCALE_AMOUNT;
-                updateIcon(targetView, scale, alpha, false);
-                View otherView = translation < 0 ? mLeftIcon : mRightIcon;
-                if (mTranslation * translation <= 0) {
-                    // The sign of the translation has changed so we need to hide the other icons
-                    updateIcon(otherView, 0, 0, true);
-                    updateIcon(mCenterIcon, 0, 0, true);
-                }
-            }
-            mTranslation = translation;
-        }
-    }
-
-    public void showAllIcons(boolean animate) {
-        float scale = 1.0f;
-        float alpha = SWIPE_RESTING_ALPHA_AMOUNT;
-        updateIcon(mRightIcon, scale, alpha, animate);
-        updateIcon(mCenterIcon, scale, alpha, animate);
-        updateIcon(mLeftIcon, scale, alpha, animate);
-    }
-
-    public void animateHideLeftRightIcon() {
-        updateIcon(mRightIcon, 0f, 0f, true);
-        updateIcon(mLeftIcon, 0f, 0f, true);
-    }
-
-    private void hideInactiveIcons(boolean animate){
-        View otherView = mTranslation < 0 ? mLeftIcon : mRightIcon;
-        updateIcon(otherView, 0, 0, animate);
-        updateIcon(mCenterIcon, 0, 0, animate);
-    }
-
-    private void updateIcon(View view, float scale, float alpha, boolean animate) {
-        if (view.getVisibility() != View.VISIBLE) {
-            return;
-        }
-        if (!animate) {
-            view.animate().cancel();
-            view.setAlpha(alpha);
-            view.setScaleX(scale);
-            view.setScaleY(scale);
-            // TODO: remove this invalidate once the property setters invalidate it properly
-            view.invalidate();
-        } else {
-            if (view.getAlpha() != alpha || view.getScaleX() != scale) {
-                view.animate()
-                        .setInterpolator(mFastOutSlowIn)
-                        .alpha(alpha)
-                        .scaleX(scale)
-                        .scaleY(scale);
-            }
-        }
-    }
-
-    private void trackMovement(MotionEvent event) {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.addMovement(event);
-        }
-    }
-
-    private void initVelocityTracker() {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-        }
-        mVelocityTracker = VelocityTracker.obtain();
-    }
-
-    private float getCurrentVelocity() {
-        if (mVelocityTracker == null) {
-            return 0;
-        }
-        mVelocityTracker.computeCurrentVelocity(1000);
-        return mVelocityTracker.getXVelocity();
-    }
-
-    public void onConfigurationChanged() {
-        initDimens();
-    }
-
-    public void reset() {
-        if (mSwipeAnimator != null) {
-            mSwipeAnimator.cancel();
-        }
-        ArrayList<View> targetViews = mCallback.getTranslationViews();
-        for (View view : targetViews) {
-            view.animate().cancel();
-        }
-        setTranslation(0.0f, true);
-        mSwipingInProgress = false;
-    }
-
-    public boolean isSwipingInProgress() {
-        return mSwipingInProgress;
-    }
-
-    public interface Callback {
-
-        /**
-         * Notifies the callback when an animation to a side page was started.
-         *
-         * @param rightPage Is the page animated to the right page?
-         */
-        void onAnimationToSideStarted(boolean rightPage);
-
-        float getPageWidth();
-
-        ArrayList<View> getTranslationViews();
-
-        View getLeftIcon();
-
-        View getCenterIcon();
-
-        View getRightIcon();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java
new file mode 100644
index 0000000..7579039
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+
+/**
+ * A view group which contains the preview of phone/camera and draws a black bar at the bottom as
+ * the fake navigation bar.
+ */
+public class KeyguardPreviewContainer extends FrameLayout {
+
+    private Drawable mBlackBarDrawable = new Drawable() {
+        @Override
+        public void draw(Canvas canvas) {
+            canvas.save();
+            canvas.clipRect(0, getHeight() - getPaddingBottom(), getWidth(), getHeight());
+            canvas.drawColor(Color.BLACK);
+            canvas.restore();
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            // noop
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+            // noop
+        }
+
+        @Override
+        public int getOpacity() {
+            return android.graphics.PixelFormat.OPAQUE;
+        }
+    };
+
+    public KeyguardPreviewContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setBackground(mBlackBarDrawable);
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        setPadding(0, 0, 0, insets.getStableInsetBottom());
+        return super.onApplyWindowInsets(insets);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 688c0d8..af30266 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -26,7 +26,7 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.tiles.UserDetailView;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 
 /**
  * Container for image of the multi user switcher (tappable).
@@ -34,6 +34,8 @@
 public class MultiUserSwitch extends FrameLayout implements View.OnClickListener {
 
     private QSPanel mQsPanel;
+    private KeyguardUserSwitcher mKeyguardUserSwitcher;
+    private boolean mKeyguardMode;
 
     public MultiUserSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -49,12 +51,26 @@
         mQsPanel = qsPanel;
     }
 
+    public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
+        mKeyguardUserSwitcher = keyguardUserSwitcher;
+    }
+
+    public void setKeyguardMode(boolean keyguardShowing) {
+        mKeyguardMode = keyguardShowing;
+    }
+
     @Override
     public void onClick(View v) {
         final UserManager um = UserManager.get(getContext());
         if (um.isUserSwitcherEnabled()) {
-            mQsPanel.showDetailAdapter(true,
-                    mQsPanel.getHost().getUserSwitcherController().userDetailAdapter);
+            if (mKeyguardMode) {
+                if (mKeyguardUserSwitcher != null) {
+                    mKeyguardUserSwitcher.show();
+                }
+            } else {
+                mQsPanel.showDetailAdapter(true,
+                        mQsPanel.getHost().getUserSwitcherController().userDetailAdapter);
+            }
         } else {
             Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
                     getContext(), v, ContactsContract.Profile.CONTENT_URI,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index fc0f2d5..b80a33b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -39,17 +39,16 @@
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.MirrorView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
-import java.util.ArrayList;
-
 public class NotificationPanelView extends PanelView implements
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
-        KeyguardPageSwipeHelper.Callback {
+        KeyguardAffordanceHelper.Callback {
 
     // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
     // changed.
@@ -59,7 +58,7 @@
     private static final float HEADER_RUBBERBAND_FACTOR = 2.15f;
     private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
 
-    private KeyguardPageSwipeHelper mPageSwiper;
+    private KeyguardAffordanceHelper mAfforanceHelper;
     private StatusBarHeaderView mHeader;
     private View mQsContainer;
     private QSPanel mQsPanel;
@@ -111,6 +110,7 @@
     private boolean mUnlockIconActive;
     private int mNotificationsHeaderCollideDistance;
     private int mUnlockMoveDistance;
+    private float mEmptyDragAmount;
 
     private Interpolator mFastOutSlowInInterpolator;
     private Interpolator mFastOutLinearInterpolator;
@@ -124,7 +124,6 @@
     private boolean mIsExpanding;
 
     private boolean mBlockTouches;
-    private ArrayList<View> mSwipeTranslationViews = new ArrayList<>();
     private int mNotificationScrimWaitDistance;
     private boolean mTwoFingerQsExpand;
     private boolean mTwoFingerQsExpandPossible;
@@ -135,6 +134,10 @@
      */
     private int mScrollYOverride = -1;
     private boolean mQsAnimatorExpand;
+    private boolean mIsLaunchTransitionFinished;
+    private boolean mIsLaunchTransitionRunning;
+    private Runnable mLaunchAnimationEndRunnable;
+    private boolean mOnlyAffordanceInThisMotion;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -167,9 +170,7 @@
         mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_linear_in);
         mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
-        mSwipeTranslationViews.add(mNotificationStackScroller);
-        mSwipeTranslationViews.add(mKeyguardStatusView);
-        mPageSwiper = new KeyguardPageSwipeHelper(this, getContext());
+        mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
     }
 
     @Override
@@ -234,7 +235,8 @@
                     getExpandedHeight(),
                     mNotificationStackScroller.getNotGoneChildCount(),
                     getHeight(),
-                    mKeyguardStatusView.getHeight());
+                    mKeyguardStatusView.getHeight(),
+                    mEmptyDragAmount);
             mClockPositionAlgorithm.run(mClockPositionResult);
             if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockY);
@@ -297,9 +299,10 @@
 
     @Override
     public void resetViews() {
+        mIsLaunchTransitionFinished = false;
         mBlockTouches = false;
         mUnlockIconActive = false;
-        mPageSwiper.reset();
+        mAfforanceHelper.reset(true);
         closeQs();
         mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
                 true /* cancelAnimators */);
@@ -354,6 +357,7 @@
         if (mBlockTouches) {
             return false;
         }
+        resetDownStates(event);
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
         if (pointerIndex < 0) {
             pointerIndex = 0;
@@ -430,6 +434,12 @@
         return !mQsExpanded && super.onInterceptTouchEvent(event);
     }
 
+    private void resetDownStates(MotionEvent event) {
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mOnlyAffordanceInThisMotion = false;
+        }
+    }
+
     @Override
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
 
@@ -464,15 +474,14 @@
         if (mBlockTouches) {
             return false;
         }
-        // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
-        // implementation.
+        resetDownStates(event);
         if ((!mIsExpanding || mHintAnimationRunning)
                 && !mQsExpanded
                 && mStatusBar.getBarState() != StatusBarState.SHADE) {
-            mPageSwiper.onTouchEvent(event);
-            if (mPageSwiper.isSwipingInProgress()) {
-                return true;
-            }
+            mAfforanceHelper.onTouchEvent(event);
+        }
+        if (mOnlyAffordanceInThisMotion) {
+            return true;
         }
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
                 && mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
@@ -951,20 +960,16 @@
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
             boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
+            KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
             if (active && !mUnlockIconActive && mTracking) {
-                mKeyguardBottomArea.getLockIcon().animate()
-                        .alpha(1f)
-                        .scaleY(LOCK_ICON_ACTIVE_SCALE)
-                        .scaleX(LOCK_ICON_ACTIVE_SCALE)
-                        .setInterpolator(mFastOutLinearInterpolator)
-                        .setDuration(150);
+                lockIcon.setImageAlpha(1.0f, true, 150, mFastOutLinearInterpolator, null);
+                lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150,
+                        mFastOutLinearInterpolator);
             } else if (!active && mUnlockIconActive && mTracking) {
-                mKeyguardBottomArea.getLockIcon().animate()
-                        .alpha(KeyguardPageSwipeHelper.SWIPE_RESTING_ALPHA_AMOUNT)
-                        .scaleY(1f)
-                        .scaleX(1f)
-                        .setInterpolator(mFastOutLinearInterpolator)
-                        .setDuration(150);
+                lockIcon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT, true,
+                        150, mFastOutLinearInterpolator, null);
+                lockIcon.setImageScale(1.0f, true, 150,
+                        mFastOutLinearInterpolator);
             }
             mUnlockIconActive = active;
         }
@@ -1093,7 +1098,7 @@
         super.onTrackingStarted();
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
-            mPageSwiper.animateHideLeftRightIcon();
+            mAfforanceHelper.animateHideLeftRightIcon();
         }
     }
 
@@ -1106,16 +1111,15 @@
         }
         if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
-            mPageSwiper.showAllIcons(true);
+            if (!mHintAnimationRunning) {
+                mAfforanceHelper.reset(true);
+            }
         }
         if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
-            mKeyguardBottomArea.getLockIcon().animate()
-                    .alpha(0f)
-                    .scaleX(2f)
-                    .scaleY(2f)
-                    .setInterpolator(mFastOutLinearInterpolator)
-                    .setDuration(100);
+            KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
+            lockIcon.setImageAlpha(0.0f, true, 100, mFastOutLinearInterpolator, null);
+            lockIcon.setImageScale(2.0f, true, 100, mFastOutLinearInterpolator);
         }
     }
 
@@ -1141,7 +1145,7 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        mPageSwiper.onConfigurationChanged();
+        mAfforanceHelper.onConfigurationChanged();
     }
 
     @Override
@@ -1159,6 +1163,8 @@
     @Override
     public void onAnimationToSideStarted(boolean rightPage) {
         boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? rightPage : !rightPage;
+        mIsLaunchTransitionRunning = true;
+        mLaunchAnimationEndRunnable = null;
         if (start) {
             mKeyguardBottomArea.launchPhone();
         } else {
@@ -1168,20 +1174,29 @@
     }
 
     @Override
+    public void onAnimationToSideEnded() {
+        mIsLaunchTransitionRunning = false;
+        mIsLaunchTransitionFinished = true;
+        if (mLaunchAnimationEndRunnable != null) {
+            mLaunchAnimationEndRunnable.run();
+            mLaunchAnimationEndRunnable = null;
+        }
+    }
+
+    @Override
     protected void onEdgeClicked(boolean right) {
         if ((right && getRightIcon().getVisibility() != View.VISIBLE)
                 || (!right && getLeftIcon().getVisibility() != View.VISIBLE)) {
             return;
         }
         mHintAnimationRunning = true;
-        mPageSwiper.startHintAnimation(right, new Runnable() {
+        mAfforanceHelper.startHintAnimation(right, new Runnable() {
             @Override
             public void run() {
                 mHintAnimationRunning = false;
                 mStatusBar.onHintFinished();
             }
         });
-        startHighlightIconAnimation(right ? getRightIcon() : getLeftIcon());
         boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? right : !right;
         if (start) {
             mStatusBar.onPhoneHintStarted();
@@ -1199,17 +1214,14 @@
     /**
      * Starts the highlight (making it fully opaque) animation on an icon.
      */
-    private void startHighlightIconAnimation(final View icon) {
-        icon.animate()
-                .alpha(1.0f)
-                .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION)
-                .setInterpolator(mFastOutSlowInInterpolator)
-                .withEndAction(new Runnable() {
+    private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
+        icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
+                mFastOutSlowInInterpolator, new Runnable() {
                     @Override
                     public void run() {
-                        icon.animate().alpha(KeyguardPageSwipeHelper.SWIPE_RESTING_ALPHA_AMOUNT)
-                                .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION)
-                                .setInterpolator(mFastOutSlowInInterpolator);
+                        icon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT,
+                                true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
+                                mFastOutSlowInInterpolator, null);
                     }
                 });
     }
@@ -1220,27 +1232,42 @@
     }
 
     @Override
-    public ArrayList<View> getTranslationViews() {
-        return mSwipeTranslationViews;
+    public void onSwipingStarted() {
+        requestDisallowInterceptTouchEvent(true);
+        mOnlyAffordanceInThisMotion = true;
     }
 
     @Override
-    public View getLeftIcon() {
+    public KeyguardAffordanceView getLeftIcon() {
         return getLayoutDirection() == LAYOUT_DIRECTION_RTL
-                ? mKeyguardBottomArea.getCameraImageView()
-                : mKeyguardBottomArea.getPhoneImageView();
+                ? mKeyguardBottomArea.getCameraView()
+                : mKeyguardBottomArea.getPhoneView();
     }
 
     @Override
-    public View getCenterIcon() {
+    public KeyguardAffordanceView getCenterIcon() {
         return mKeyguardBottomArea.getLockIcon();
     }
 
     @Override
-    public View getRightIcon() {
+    public KeyguardAffordanceView getRightIcon() {
         return getLayoutDirection() == LAYOUT_DIRECTION_RTL
-                ? mKeyguardBottomArea.getPhoneImageView()
-                : mKeyguardBottomArea.getCameraImageView();
+                ? mKeyguardBottomArea.getPhoneView()
+                : mKeyguardBottomArea.getCameraView();
+    }
+
+    @Override
+    public View getLeftPreview() {
+        return getLayoutDirection() == LAYOUT_DIRECTION_RTL
+                ? mKeyguardBottomArea.getCameraPreview()
+                : mKeyguardBottomArea.getPhonePreview();
+    }
+
+    @Override
+    public View getRightPreview() {
+        return getLayoutDirection() == LAYOUT_DIRECTION_RTL
+                ? mKeyguardBottomArea.getPhonePreview()
+                : mKeyguardBottomArea.getCameraPreview();
     }
 
     @Override
@@ -1262,6 +1289,22 @@
     }
 
     @Override
+    protected boolean fullyExpandedClearAllVisible() {
+        return mNotificationStackScroller.isDismissViewNotGone()
+                && mNotificationStackScroller.isScrolledToBottom();
+    }
+
+    @Override
+    protected boolean isClearAllVisible() {
+        return mNotificationStackScroller.isDismissViewVisible();
+    }
+
+    @Override
+    protected int getClearAllHeight() {
+        return mNotificationStackScroller.getDismissViewHeight();
+    }
+
+    @Override
     protected boolean isTrackingBlocked() {
         return mConflictingQsExpansionGesture && mQsExpanded;
     }
@@ -1282,4 +1325,27 @@
     public boolean shouldDelayChildPressedState() {
         return true;
     }
+
+    public boolean isLaunchTransitionFinished() {
+        return mIsLaunchTransitionFinished;
+    }
+
+    public boolean isLaunchTransitionRunning() {
+        return mIsLaunchTransitionRunning;
+    }
+
+    public void setLaunchTransitionEndRunnable(Runnable r) {
+        mLaunchAnimationEndRunnable = r;
+    }
+
+    public void setEmptyDragAmount(float amount) {
+        float factor = 1f;
+        if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
+            factor = 0.6f;
+        } else if (!mStatusBar.hasNotifications()) {
+            factor = 0.4f;
+        }
+        mEmptyDragAmount = amount * factor;
+        positionClockAndNotifications();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index f41e78d..7c6e47c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -17,23 +17,71 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
+import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewStub;
 import android.widget.FrameLayout;
 
+import com.android.systemui.R;
+
 /**
  * The container with notification stack scroller and quick settings inside.
  */
-public class NotificationsQuickSettingsContainer extends FrameLayout {
+public class NotificationsQuickSettingsContainer extends FrameLayout
+        implements ViewStub.OnInflateListener {
+
+    private View mScrollView;
+    private View mUserSwitcher;
+    private View mStackScroller;
+    private boolean mInflated;
 
     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mScrollView = findViewById(R.id.scroll_view);
+        mStackScroller = findViewById(R.id.notification_stack_scroller);
+        ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
+        userSwitcher.setOnInflateListener(this);
+        mUserSwitcher = userSwitcher;
+    }
+
+    @Override
     protected boolean fitSystemWindows(Rect insets) {
         setPadding(0, 0, 0, insets.bottom);
         insets.bottom = 0;
         return true;
     }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
+
+        // Invert the order of the scroll view and user switcher such that the notifications receive
+        // touches first but the panel gets drawn above.
+        if (child == mScrollView) {
+            return super.drawChild(canvas, mStackScroller, drawingTime);
+        } else if (child == mStackScroller) {
+            return super.drawChild(canvas, userSwitcherVisible ? mUserSwitcher : mScrollView,
+                    drawingTime);
+        } else if (child == mUserSwitcher) {
+            return super.drawChild(canvas, userSwitcherVisible ? mScrollView : mUserSwitcher,
+                    drawingTime);
+        } else {
+            return super.drawChild(canvas, child, drawingTime);
+        }
+    }
+
+    @Override
+    public void onInflate(ViewStub stub, View inflated) {
+        if (stub == mUserSwitcher) {
+            mUserSwitcher = inflated;
+            mInflated = true;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7fb5693..3ec2395 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -462,6 +462,16 @@
     protected void fling(float vel, boolean expand) {
         cancelPeek();
         float target = expand ? getMaxPanelHeight() : 0.0f;
+
+        // Hack to make the expand transition look nice when clear all button is visible - we make
+        // the animation only to the last notification, and then jump to the maximum panel height so
+        // clear all just fades in and the decelerating motion is towards the last notification.
+        final boolean clearAllExpandHack = expand && fullyExpandedClearAllVisible()
+                && mExpandedHeight < getMaxPanelHeight() - getClearAllHeight()
+                && !isClearAllVisible();
+        if (clearAllExpandHack) {
+            target = getMaxPanelHeight() - getClearAllHeight();
+        }
         if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
             notifyExpandingFinished();
             return;
@@ -490,9 +500,32 @@
 
             @Override
             public void onAnimationEnd(Animator animation) {
-                mHeightAnimator = null;
-                if (!mCancelled) {
-                    notifyExpandingFinished();
+                if (clearAllExpandHack && !mCancelled) {
+                    mHeightAnimator = createHeightAnimator(getMaxPanelHeight());
+                    mHeightAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+                    mHeightAnimator.setDuration(350);
+                    mHeightAnimator.addListener(new AnimatorListenerAdapter() {
+                        private boolean mCancelled;
+
+                        @Override
+                        public void onAnimationCancel(Animator animation) {
+                            mCancelled = true;
+                        }
+
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mHeightAnimator = null;
+                            if (!mCancelled) {
+                                notifyExpandingFinished();
+                            }
+                        }
+                    });
+                    mHeightAnimator.start();
+                } else {
+                    mHeightAnimator = null;
+                    if (!mCancelled) {
+                        notifyExpandingFinished();
+                    }
                 }
             }
         });
@@ -878,4 +911,16 @@
     protected abstract float getPeekHeight();
 
     protected abstract float getCannedFlingDurationFactor();
+
+    /**
+     * @return whether "Clear all" button will be visible when the panel is fully expanded
+     */
+    protected abstract boolean fullyExpandedClearAllVisible();
+
+    protected abstract boolean isClearAllVisible();
+
+    /**
+     * @return the height of the clear all button, in pixels
+     */
+    protected abstract int getClearAllHeight();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e4e67c9..044f69c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -53,7 +53,6 @@
 import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.inputmethodservice.InputMethodService;
@@ -63,6 +62,7 @@
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -92,11 +92,13 @@
 import android.view.ViewStub;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -115,6 +117,7 @@
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.GestureRecorder;
@@ -126,6 +129,7 @@
 import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
@@ -155,7 +159,7 @@
 import java.util.List;
 
 public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
-        DragDownHelper.OnDragDownListener, ActivityStarter {
+        DragDownHelper.DragDownCallback, ActivityStarter {
     static final String TAG = "PhoneStatusBar";
     public static final boolean DEBUG = BaseStatusBar.DEBUG;
     public static final boolean SPEW = false;
@@ -201,6 +205,9 @@
             .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
             .build();
 
+    public static final int FADE_KEYGUARD_START_DELAY = 100;
+    public static final int FADE_KEYGUARD_DURATION = 300;
+
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
@@ -217,6 +224,7 @@
     KeyguardUserSwitcher mKeyguardUserSwitcher;
     FlashlightController mFlashlightController;
     UserSwitcherController mUserSwitcherController;
+    NextAlarmController mNextAlarmController;
     KeyguardMonitor mKeyguardMonitor;
 
     int mNaturalBarHeight = -1;
@@ -275,7 +283,6 @@
     private long mKeyguardFadingAwayDuration;
 
     int mKeyguardMaxNotificationCount;
-    View mDateTimeView;
 
     // carrier/wifi label
     private TextView mCarrierLabel;
@@ -397,6 +404,8 @@
     private boolean mDozing;
 
     private Interpolator mLinearOutSlowIn;
+    private Interpolator mLinearInterpolator = new LinearInterpolator();
+    private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator();
     private Interpolator mAlphaIn = new PathInterpolator(0f, 0.2f, 1f, 1f);
     private Interpolator mAlphaOut = new PathInterpolator(0f, 0f, 0.8f, 1f);
 
@@ -441,6 +450,10 @@
     private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
 
     private int mDrawCount;
+    private Runnable mLaunchTransitionEndRunnable;
+    private boolean mLaunchTransitionFadingAway;
+
+    private boolean mHasNotifications;
 
     private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD
             | ViewState.LOCATION_TOP_STACK_PEEKING
@@ -666,6 +679,15 @@
         SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
                         R.layout.status_bar_notification_speed_bump, mStackScroller, false);
         mStackScroller.setSpeedBumpView(speedBump);
+        mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
+                R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
+        mDismissView.setOnButtonClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                clearAllNotifications();
+            }
+        });
+        mStackScroller.setDismissView(mDismissView);
         mExpandedContents = mStackScroller;
 
         mScrimController = new ScrimController(mStatusBarWindow.findViewById(R.id.scrim_behind),
@@ -682,12 +704,6 @@
                 (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                         R.id.keyguard_indication_text));
 
-        mDateTimeView = mHeader.findViewById(R.id.datetime);
-        if (mDateTimeView != null) {
-            mDateTimeView.setOnClickListener(mClockClickListener);
-            mDateTimeView.setEnabled(true);
-        }
-
         mTickerEnabled = res.getBoolean(R.bool.enable_ticker);
         if (mTickerEnabled) {
             final ViewStub tickerStub = (ViewStub) mStatusBarView.findViewById(R.id.ticker_stub);
@@ -731,9 +747,6 @@
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
 
-        mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
-                (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader);
-
         mNetworkController.addSignalCluster(signalCluster);
         signalCluster.setNetworkController(mNetworkController);
         final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
@@ -767,8 +780,14 @@
         mFlashlightController = new FlashlightController(mContext);
         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
         mUserSwitcherController = new UserSwitcherController(mContext);
+        mNextAlarmController = new NextAlarmController(mContext);
         mKeyguardMonitor = new KeyguardMonitor();
 
+        mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
+                (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader,
+                mUserSwitcherController);
+
+
         // Set up the quick settings tile panel
         mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
         if (mQSPanel != null) {
@@ -793,6 +812,7 @@
         mUserInfoController.reloadUserInfo();
 
         mHeader.setBatteryController(mBatteryController);
+        mHeader.setNextAlarmController(mNextAlarmController);
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mBroadcastReceiver.onReceive(mContext,
@@ -816,6 +836,73 @@
         return mStatusBarView;
     }
 
+    private void clearAllNotifications() {
+
+        // animate-swipe all dismissable notifications, then animate the shade closed
+        int numChildren = mStackScroller.getChildCount();
+
+        final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
+        for (int i = 0; i < numChildren; i++) {
+            final View child = mStackScroller.getChildAt(i);
+            if (mStackScroller.canChildBeDismissed(child)) {
+                if (child.getVisibility() == View.VISIBLE) {
+                    viewsToHide.add(child);
+                }
+            }
+        }
+        if (viewsToHide.isEmpty()) {
+            animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+            return;
+        }
+
+        mPostCollapseCleanup = new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mBarService.onClearAllNotifications(mCurrentUserId);
+                } catch (Exception ex) { }
+            }
+        };
+
+        performDismissAllAnimations(viewsToHide);
+
+    }
+
+    private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
+        Runnable animationFinishAction = new Runnable() {
+            @Override
+            public void run() {
+                mStackScroller.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mStackScroller.setDismissAllInProgress(false);
+                    }
+                });
+                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+            }
+        };
+
+        // let's disable our normal animations
+        mStackScroller.setDismissAllInProgress(true);
+
+        // Decrease the delay for every row we animate to give the sense of
+        // accelerating the swipes
+        int rowDelayDecrement = 10;
+        int currentDelay = 140;
+        int totalDelay = 0;
+        int numItems = hideAnimatedList.size();
+        for (int i = 0; i < numItems; i++) {
+            View view = hideAnimatedList.get(i);
+            Runnable endRunnable = null;
+            if (i == numItems - 1) {
+                endRunnable = animationFinishAction;
+            }
+            mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
+            currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
+            totalDelay += currentDelay;
+        }
+    }
+
     /**
      * Hack to improve glyph rasterization for scaled text views.
      */
@@ -1228,8 +1315,12 @@
             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
 
             if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
-                    && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
-                animateCollapsePanels();
+                    && !mNotificationPanel.isTracking()) {
+                if (mState == StatusBarState.SHADE) {
+                    animateCollapsePanels();
+                } else if (mState == StatusBarState.SHADE_LOCKED) {
+                    goToKeyguard();
+                }
             }
         }
         setAreThereNotifications();
@@ -1326,10 +1417,32 @@
         }
         updateRowStates();
         updateSpeedbump();
+        updateClearAll();
+
         mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
         mShadeUpdates.check();
     }
 
+    private void updateClearAll() {
+        boolean showDismissView = false;
+        if (mState != StatusBarState.KEYGUARD) {
+            for (int i = 0; i < mNotificationData.size(); i++) {
+                Entry entry = mNotificationData.get(i);
+                if (entry.row.getParent() == null) {
+                    // This view isn't even added, so the stack scroller doesn't
+                    // know about it. Ignore completely.
+                    continue;
+                }
+                if (entry.row.getVisibility() != View.GONE && entry.expanded != null
+                        && entry.notification.isClearable()) {
+                    showDismissView = true;
+                    break;
+                }
+            }
+        }
+        mStackScroller.updateDismissView(showDismissView);
+    }
+
     private void updateSpeedbump() {
         int speedbumpIndex = -1;
         int currentIndex = 0;
@@ -1503,6 +1616,9 @@
         findAndUpdateMediaNotifications();
 
         updateCarrierLabelVisibility(false);
+
+        // TODO: Multiuser handling!
+        mHasNotifications = any;
     }
 
     public void findAndUpdateMediaNotifications() {
@@ -1518,7 +1634,7 @@
                     final MediaSession.Token token = entry.notification.getNotification().extras
                             .getParcelable(Notification.EXTRA_MEDIA_SESSION);
                     if (token != null) {
-                        controller = new MediaController(token);
+                        controller = new MediaController(mContext, token);
                         if (controller != null) {
                             // we've got a live one, here
                             mediaNotification = entry;
@@ -1548,7 +1664,7 @@
                                 continue;
                             default:
                                 // now to see if we have one like this
-                                final String pkg = aController.getSessionInfo().getPackageName();
+                                final String pkg = aController.getPackageName();
 
                                 for (int i = 0; i < N; i++) {
                                     final Entry entry = mNotificationData.get(i);
@@ -1693,7 +1809,7 @@
                                 + " to "
                                 + mBackdropBack.getDrawable());
                     }
-                    mBackdropFront.animate().withLayer()
+                    mBackdropFront.animate()
                             .setDuration(250)
                             .alpha(0f).withEndAction(mHideBackdropFront);
                 }
@@ -1705,16 +1821,29 @@
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
                 }
-                mBackdrop.animate().withLayer()
-                        .alpha(0f).withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        mBackdrop.setVisibility(View.GONE);
-                        mBackdropFront.animate().cancel();
-                        mBackdropBack.animate().cancel();
-                        mHandler.post(mHideBackdropFront);
-                    }
-                });
+                mBackdrop.animate()
+                        .alpha(0f)
+                        .setInterpolator(mBackdropInterpolator)
+                        .setDuration(300)
+                        .setStartDelay(0)
+                        .withEndAction(new Runnable() {
+                            @Override
+                            public void run() {
+                                mBackdrop.setVisibility(View.GONE);
+                                mBackdropFront.animate().cancel();
+                                mBackdropBack.animate().cancel();
+                                mHandler.post(mHideBackdropFront);
+                            }
+                        });
+                if (mKeyguardFadingAway) {
+                    mBackdrop.animate()
+
+                            // Make it disappear faster, as the focus should be on the activity behind.
+                            .setDuration(mKeyguardFadingAwayDuration / 2)
+                            .setStartDelay(mKeyguardFadingAwayDelay)
+                            .setInterpolator(mLinearInterpolator)
+                            .start();
+                }
             }
         }
     }
@@ -1728,7 +1857,8 @@
     }
 
     private int adjustDisableFlags(int state) {
-        if (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit) {
+        if (!mLaunchTransitionFadingAway
+                && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
         }
@@ -1995,6 +2125,10 @@
     public void animateCollapsePanels(int flags, boolean force) {
         if (!force &&
                 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
+            if (mPostCollapseCleanup != null) {
+                mPostCollapseCleanup.run();
+                mPostCollapseCleanup = null;
+            }
             return;
         }
         if (SPEW) {
@@ -2217,6 +2351,13 @@
     }
 
     @Override // CommandQueue
+    public void buzzBeepBlinked() {
+        if (mDozeServiceHost != null) {
+            mDozeServiceHost.fireBuzzBeepBlinked();
+        }
+    }
+
+    @Override // CommandQueue
     public void setSystemUiVisibility(int vis, int mask) {
         final int oldVal = mSystemUiVisibility;
         final int newVal = (oldVal&~mask) | (vis&mask);
@@ -2666,6 +2807,9 @@
         if (mBatteryController != null) {
             mBatteryController.dump(fd, pw, args);
         }
+        if (mNextAlarmController != null) {
+            mNextAlarmController.dump(fd, pw, args);
+        }
     }
 
     private String hunStateToString(Entry entry) {
@@ -2722,16 +2866,25 @@
     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned) {
         if (onlyProvisioned && !isDeviceProvisioned()) return;
 
+        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
         dismissKeyguardThenExecute(new OnDismissAction() {
             @Override
             public boolean onDismiss() {
-                try {
-                    // Dismiss the lock screen when Settings starts.
-                    ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-                } catch (RemoteException e) {
-                }
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+                AsyncTask.execute(new Runnable() {
+                    public void run() {
+                        try {
+                            intent.setFlags(
+                                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                            mContext.startActivityAsUser(
+                                    intent, new UserHandle(UserHandle.USER_CURRENT));
+                            if (keyguardShowing) {
+                                mWindowManagerService.overridePendingAppTransition(
+                                        null, 0, 0, null);
+                            }
+                        } catch (RemoteException e) {
+                        }
+                    }
+                });
                 animateCollapsePanels();
 
                 return DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
@@ -2752,11 +2905,9 @@
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
-                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                    String reason = intent.getStringExtra("reason");
-                    if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
-                        flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
-                    }
+                String reason = intent.getStringExtra("reason");
+                if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
+                    flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
                 }
                 animateCollapsePanels(flags);
             }
@@ -2795,9 +2946,20 @@
     };
 
     @Override
-    protected void dismissKeyguardThenExecute(OnDismissAction action) {
+    protected void dismissKeyguardThenExecute(final OnDismissAction action) {
         if (mStatusBarKeyguardViewManager.isShowing()) {
-            mStatusBarKeyguardViewManager.dismissWithAction(action);
+            if (UnlockMethodCache.getInstance(mContext).isMethodInsecure()
+                    && mNotificationPanel.isLaunchTransitionRunning()) {
+                action.onDismiss();
+                mNotificationPanel.setLaunchTransitionEndRunnable(new Runnable() {
+                    @Override
+                    public void run() {
+                        mStatusBarKeyguardViewManager.dismiss();
+                    }
+                });
+            } else {
+                mStatusBarKeyguardViewManager.dismissWithAction(action);
+            }
         } else {
             action.onDismiss();
         }
@@ -3170,6 +3332,52 @@
         mLeaveOpenOnKeyguardHide = false;
     }
 
+    public boolean isInLaunchTransition() {
+        return mNotificationPanel.isLaunchTransitionRunning()
+                || mNotificationPanel.isLaunchTransitionFinished();
+    }
+
+    /**
+     * Fades the content of the keyguard away after the launch transition is done.
+     *
+     * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
+     *                     starts
+     * @param endRunnable the runnable to be run when the transition is done
+     */
+    public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
+            final Runnable endRunnable) {
+        Runnable hideRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mLaunchTransitionFadingAway = true;
+                if (beforeFading != null) {
+                    beforeFading.run();
+                }
+                mNotificationPanel.setAlpha(1);
+                mNotificationPanel.animate()
+                        .alpha(0)
+                        .setStartDelay(FADE_KEYGUARD_START_DELAY)
+                        .setDuration(FADE_KEYGUARD_DURATION)
+                        .withLayer()
+                        .withEndAction(new Runnable() {
+                            @Override
+                            public void run() {
+                                mNotificationPanel.setAlpha(1);
+                                if (endRunnable != null) {
+                                    endRunnable.run();
+                                }
+                                mLaunchTransitionFadingAway = false;
+                            }
+                        });
+            }
+        };
+        if (mNotificationPanel.isLaunchTransitionRunning()) {
+            mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
+        } else {
+            hideRunnable.run();
+        }
+    }
+
     public void hideKeyguard() {
         setBarState(StatusBarState.SHADE);
         if (mLeaveOpenOnKeyguardHide) {
@@ -3204,8 +3412,8 @@
 
     private void updatePublicMode() {
         setLockscreenPublicMode(
-                (mStatusBarKeyguardViewManager.isShowing() || 
-                    mStatusBarKeyguardViewManager.isOccluded())
+                (mStatusBarKeyguardViewManager.isShowing() ||
+                        mStatusBarKeyguardViewManager.isOccluded())
                 && mStatusBarKeyguardViewManager.isSecure());
     }
 
@@ -3315,7 +3523,7 @@
 
     private void showBouncer() {
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
-            mWaitingForKeyguardExit = true;
+            mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
             mStatusBarKeyguardViewManager.dismiss();
         }
     }
@@ -3358,6 +3566,10 @@
     }
 
     public void onTrackingStarted() {
+        if (mPostCollapseCleanup != null) {
+            mPostCollapseCleanup.run();
+            mPostCollapseCleanup = null;
+        }
     }
 
     public void onUnlockHintStarted() {
@@ -3397,8 +3609,17 @@
     // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
 
     @Override
-    public void onDraggedDown(View startingChild) {
-        goToLockedShade(startingChild);
+    public boolean onDraggedDown(View startingChild) {
+        if (mHasNotifications) {
+
+            // We have notifications, go to locked shade.
+            goToLockedShade(startingChild);
+            return true;
+        } else {
+
+            // No notifications - abort gesture.
+            return false;
+        }
     }
 
     @Override
@@ -3406,6 +3627,7 @@
         mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
     }
 
+    @Override
     public void onThresholdReached() {
         mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
     }
@@ -3415,6 +3637,11 @@
         mStackScroller.removeLongPressCallback();
     }
 
+    @Override
+    public void setEmptyDragAmount(float amount) {
+        mNotificationPanel.setEmptyDragAmount(amount);
+    }
+
     /**
      * If secure with redaction: Show bouncer, go to unlocked shade.
      *
@@ -3525,6 +3752,10 @@
         notifyUiVisibilityChanged(mSystemUiVisibility);
     }
 
+    public boolean hasNotifications() {
+        return mHasNotifications;
+    }
+
     private final class ShadeUpdates {
         private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
         private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
@@ -3562,6 +3793,12 @@
 
         private DozeService mCurrentDozeService;
 
+        public void fireBuzzBeepBlinked() {
+            for (Callback callback : mCallbacks) {
+                callback.onBuzzBeepBlinked();
+            }
+        }
+
         public void fireNewNotifications() {
             for (Callback callback : mCallbacks) {
                 callback.onNewNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c464f31..eb42401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -44,12 +44,13 @@
     private static final int TAG_KEY_ANIM = R.id.scrim;
 
     private static final int NUM_TEASES = 3;
-    private static final long TEASE_IN_ANIMATION_DURATION = 500;
-    private static final long TEASE_VISIBLE_DURATION = 3000;
+    private static final long TEASE_IN_ANIMATION_DURATION = 1000;
+    private static final long TEASE_VISIBLE_DURATION = 2000;
     private static final long TEASE_OUT_ANIMATION_DURATION = 1000;
     private static final long TEASE_INVISIBLE_DURATION = 1000;
     private static final long TEASE_DURATION = TEASE_IN_ANIMATION_DURATION
             + TEASE_VISIBLE_DURATION + TEASE_OUT_ANIMATION_DURATION + TEASE_INVISIBLE_DURATION;
+    private static final long PRE_TEASE_DELAY = 1000;
 
     private final View mScrimBehind;
     private final View mScrimInFront;
@@ -70,7 +71,6 @@
     private boolean mAnimationStarted;
     private boolean mDozing;
     private int mTeasesRemaining;
-
     private final Interpolator mInterpolator = new DecelerateInterpolator();
 
     public ScrimController(View scrimBehind, View scrimInFront) {
@@ -128,8 +128,8 @@
     public long tease() {
         if (!mDozing) return 0;
         mTeasesRemaining = NUM_TEASES;
-        mScrimInFront.post(mTeaseIn);
-        return NUM_TEASES * TEASE_DURATION;
+        mScrimInFront.postDelayed(mTeaseIn, PRE_TEASE_DELAY);
+        return PRE_TEASE_DELAY + NUM_TEASES * TEASE_DURATION;
     }
 
     private void cancelTeasing() {
@@ -148,7 +148,10 @@
     }
 
     private void updateScrims() {
-        if ((!mKeyguardShowing && !mBouncerShowing) || mAnimateKeyguardFadingOut) {
+        if (mAnimateKeyguardFadingOut) {
+            setScrimInFrontColor(0f);
+            setScrimBehindColor(0f);
+        }else if (!mKeyguardShowing && !mBouncerShowing) {
             updateScrimNormal();
             setScrimInFrontColor(0);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 2f88e21..27d66d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.AlarmClockInfo;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Outline;
@@ -31,17 +33,20 @@
 import android.widget.Switch;
 import android.widget.TextView;
 
+import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
+import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
 /**
  * The view to manage the header area in the expanded status bar.
  */
 public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener,
-        BatteryController.BatteryStateChangeCallback {
+        BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback {
 
     private boolean mExpanded;
     private boolean mListening;
@@ -51,7 +56,8 @@
 
     private ViewGroup mSystemIconsContainer;
     private View mSystemIconsSuperContainer;
-    private View mDateTime;
+    private View mDateGroup;
+    private View mClock;
     private View mTime;
     private View mAmPm;
     private View mKeyguardCarrierText;
@@ -67,9 +73,12 @@
     private Switch mQsDetailHeaderSwitch;
     private View mEmergencyCallsOnly;
     private TextView mBatteryLevel;
+    private TextView mAlarmStatus;
 
     private boolean mShowEmergencyCallsOnly;
     private boolean mKeyguardUserSwitcherShowing;
+    private boolean mAlarmShowing;
+    private AlarmClockInfo mNextAlarm;
 
     private int mCollapsedHeight;
     private int mExpandedHeight;
@@ -83,9 +92,13 @@
     private int mMultiUserKeyguardMargin;
     private int mSystemIconsSwitcherHiddenExpandedMargin;
     private int mClockMarginBottomExpanded;
+    private int mClockMarginBottomCollapsed;
     private int mMultiUserSwitchWidthCollapsed;
     private int mMultiUserSwitchWidthExpanded;
+    private int mMultiUserSwitchWidthKeyguard;
     private int mBatteryPaddingEnd;
+    private int mBatteryMarginExpanded;
+    private int mBatteryMarginKeyguard;
 
     /**
      * In collapsed QS, the clock and avatar are scaled down a bit post-layout to allow for a nice
@@ -93,10 +106,13 @@
      */
     private float mClockCollapsedScaleFactor;
     private float mAvatarCollapsedScaleFactor;
+    private float mAvatarKeyguardScaleFactor;
 
     private ActivityStarter mActivityStarter;
     private BatteryController mBatteryController;
+    private NextAlarmController mNextAlarmController;
     private QSPanel mQSPanel;
+    private KeyguardUserSwitcher mKeyguardUserSwitcher;
 
     private final Rect mClipBounds = new Rect();
     private final StatusIconClipper mStatusIconClipper = new StatusIconClipper();
@@ -111,7 +127,8 @@
         mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container);
         mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
         mSystemIconsSuperContainer.setOnClickListener(this);
-        mDateTime = findViewById(R.id.datetime);
+        mDateGroup = findViewById(R.id.date_group);
+        mClock = findViewById(R.id.clock);
         mTime = findViewById(R.id.time_view);
         mAmPm = findViewById(R.id.am_pm_view);
         mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text);
@@ -127,6 +144,8 @@
         mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
         mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only);
         mBatteryLevel = (TextView) findViewById(R.id.battery_level);
+        mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
+        mAlarmStatus.setOnClickListener(this);
         loadDimens();
         updateVisibilities();
         updateClockScale();
@@ -173,18 +192,29 @@
                 R.dimen.system_icons_switcher_hidden_expanded_margin);
         mClockMarginBottomExpanded =
                 getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin);
+        mClockMarginBottomCollapsed =
+                getResources().getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin);
         mMultiUserSwitchWidthCollapsed =
                 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed);
         mMultiUserSwitchWidthExpanded =
                 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_expanded);
+        mMultiUserSwitchWidthKeyguard =
+                getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_keyguard);
         mAvatarCollapsedScaleFactor =
                 getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_collapsed_size)
                 / (float) mMultiUserAvatar.getLayoutParams().width;
+        mAvatarKeyguardScaleFactor =
+                getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size)
+                        / (float) mMultiUserAvatar.getLayoutParams().width;
         mClockCollapsedScaleFactor =
                 (float) getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size)
                 / (float) getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
         mBatteryPaddingEnd =
                 getResources().getDimensionPixelSize(R.dimen.battery_level_padding_end);
+        mBatteryMarginExpanded =
+                getResources().getDimensionPixelSize(R.dimen.header_battery_margin_expanded);
+        mBatteryMarginKeyguard =
+                getResources().getDimensionPixelSize(R.dimen.header_battery_margin_keyguard);
     }
 
     public void setActivityStarter(ActivityStarter activityStarter) {
@@ -195,6 +225,10 @@
         mBatteryController = batteryController;
     }
 
+    public void setNextAlarmController(NextAlarmController nextAlarmController) {
+        mNextAlarmController = nextAlarmController;
+    }
+
     public int getCollapsedHeight() {
         return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight;
     }
@@ -208,7 +242,7 @@
             return;
         }
         mListening = listening;
-        updateBatteryListening();
+        updateListeners();
     }
 
     public void setExpanded(boolean expanded, boolean overscrolled) {
@@ -232,6 +266,7 @@
             updateAvatarScale();
             updateClockLp();
             updateBatteryLevelPaddingEnd();
+            updateBatteryLevelLp();
             mStatusIconClipper.update();
         }
     }
@@ -239,7 +274,7 @@
     private void updateHeights() {
         boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
         int height;
-        if (mExpanded) {
+        if (mExpanded && !mOverscrolled) {
             height = mExpandedHeight;
         } else if (onKeyguardAndCollapsed) {
             height = mKeyguardHeight;
@@ -280,10 +315,15 @@
         } else {
             setBackgroundResource(R.drawable.notification_header_bg);
         }
-        mDateTime.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
+        mDateGroup.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
+        mClock.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
         mKeyguardCarrierText.setVisibility(onKeyguardAndCollapsed ? View.VISIBLE : View.GONE);
-        mDateCollapsed.setVisibility(mExpanded && !mOverscrolled ? View.GONE : View.VISIBLE);
-        mDateExpanded.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE);
+        mDateCollapsed.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing
+                ? View.VISIBLE : View.GONE);
+        mDateExpanded.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing
+                ? View.GONE : View.VISIBLE);
+        mAlarmStatus.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing
+                ? View.VISIBLE : View.GONE);
         mSettingsButton.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE);
         mQsDetailHeader.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
         if (mStatusIcons != null) {
@@ -298,6 +338,9 @@
                 ? VISIBLE : GONE);
         mBatteryLevel.setVisibility(mKeyguardShowing && mCharging || mExpanded && !mOverscrolled
                 ? View.VISIBLE : View.GONE);
+        if (mExpanded && !mOverscrolled && mKeyguardUserSwitcherShowing) {
+            mKeyguardUserSwitcher.hide();
+        }
     }
 
     private void updateSystemIconsLayoutParams() {
@@ -314,21 +357,26 @@
         mSystemIconsSuperContainer.setLayoutParams(lp);
     }
 
-    private void updateBatteryListening() {
+    private void updateListeners() {
         if (mListening) {
             mBatteryController.addStateChangedCallback(this);
+            mNextAlarmController.addStateChangedCallback(this);
         } else {
             mBatteryController.removeStateChangedCallback(this);
+            mNextAlarmController.removeStateChangedCallback(this);
         }
     }
 
     private void updateAvatarScale() {
-        if (!mExpanded || mOverscrolled) {
-            mMultiUserSwitch.setScaleX(mAvatarCollapsedScaleFactor);
-            mMultiUserSwitch.setScaleY(mAvatarCollapsedScaleFactor);
-        } else {
+        if (mExpanded && !mOverscrolled) {
             mMultiUserSwitch.setScaleX(1f);
             mMultiUserSwitch.setScaleY(1f);
+        } else if (mKeyguardShowing) {
+            mMultiUserSwitch.setScaleX(mAvatarKeyguardScaleFactor);
+            mMultiUserSwitch.setScaleY(mAvatarKeyguardScaleFactor);
+        } else {
+            mMultiUserSwitch.setScaleX(mAvatarCollapsedScaleFactor);
+            mMultiUserSwitch.setScaleY(mAvatarCollapsedScaleFactor);
         }
     }
 
@@ -370,11 +418,26 @@
         // could not care less
     }
 
+    @Override
+    public void onNextAlarmChanged(AlarmClockInfo nextAlarm) {
+        mNextAlarm = nextAlarm;
+        if (nextAlarm != null) {
+            mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
+        }
+        mAlarmShowing = nextAlarm != null;
+        updateVisibilities();
+    }
+
+
     private void updateClickTargets() {
         setClickable(!mKeyguardShowing || mExpanded);
-        mDateTime.setClickable(mExpanded);
-        mMultiUserSwitch.setClickable(mExpanded);
+
+        boolean keyguardSwitcherAvailable =
+                mKeyguardUserSwitcher != null && mKeyguardShowing && !mExpanded;
+        mMultiUserSwitch.setClickable(mExpanded || keyguardSwitcherAvailable);
+        mMultiUserSwitch.setKeyguardMode(keyguardSwitcherAvailable);
         mSystemIconsSuperContainer.setClickable(mExpanded);
+        mAlarmStatus.setClickable(mNextAlarm != null && mNextAlarm.getShowIntent() != null);
     }
 
     private void updateZTranslation() {
@@ -395,29 +458,29 @@
     }
 
     private void updateClockLp() {
-        int marginBottom = mExpanded && !mOverscrolled ? mClockMarginBottomExpanded : 0;
-        LayoutParams lp = (LayoutParams) mDateTime.getLayoutParams();
-        int rule = mExpanded && !mOverscrolled ? TRUE : 0;
-        if (marginBottom != lp.bottomMargin
-                || lp.getRules()[RelativeLayout.ALIGN_PARENT_BOTTOM] != rule) {
+        int marginBottom = mExpanded && !mOverscrolled
+                ? mClockMarginBottomExpanded
+                : mClockMarginBottomCollapsed;
+        LayoutParams lp = (LayoutParams) mDateGroup.getLayoutParams();
+        if (marginBottom != lp.bottomMargin) {
             lp.bottomMargin = marginBottom;
-            lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, rule);
-            mDateTime.setLayoutParams(lp);
+            mDateGroup.setLayoutParams(lp);
         }
     }
 
     private void updateMultiUserSwitch() {
         int marginEnd;
+        int width;
         if (mExpanded && !mOverscrolled) {
             marginEnd = mMultiUserExpandedMargin;
+            width = mMultiUserSwitchWidthExpanded;
         } else if (mKeyguardShowing) {
             marginEnd = mMultiUserKeyguardMargin;
+            width = mMultiUserSwitchWidthKeyguard;
         } else {
             marginEnd = mMultiUserCollapsedMargin;
+            width = mMultiUserSwitchWidthCollapsed;
         }
-        int width = mExpanded && !mOverscrolled
-                ? mMultiUserSwitchWidthExpanded
-                : mMultiUserSwitchWidthCollapsed;
         MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams();
         if (marginEnd != lp.getMarginEnd() || lp.width != width) {
             lp.setMarginEnd(marginEnd);
@@ -426,6 +489,17 @@
         }
     }
 
+    private void updateBatteryLevelLp() {
+        int marginStart = mExpanded && !mOverscrolled
+                ? mBatteryMarginExpanded
+                : mBatteryMarginKeyguard;
+        MarginLayoutParams lp = (MarginLayoutParams) mBatteryLevel.getLayoutParams();
+        if (marginStart != lp.getMarginStart()) {
+            lp.setMarginStart(marginStart);
+            mBatteryLevel.setLayoutParams(lp);
+        }
+    }
+
     public void setExpansion(float t) {
         float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight);
         if (height < mCollapsedHeight) {
@@ -472,6 +546,7 @@
         updateMultiUserSwitch();
         updateClickTargets();
         updateBatteryLevelPaddingEnd();
+        updateAvatarScale();
         mStatusIconClipper.update();
     }
 
@@ -490,6 +565,11 @@
             startSettingsActivity();
         } else if (v == mSystemIconsSuperContainer) {
             startBatteryActivity();
+        } else if (v == mAlarmStatus && mNextAlarm != null) {
+            PendingIntent showIntent = mNextAlarm.getShowIntent();
+            if (showIntent != null && showIntent.isActivity()) {
+                mActivityStarter.startActivity(showIntent.getIntent());
+            }
         }
     }
 
@@ -509,6 +589,11 @@
         mMultiUserSwitch.setQsPanel(qsp);
     }
 
+    public void setKeyguarUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
+        mKeyguardUserSwitcher = keyguardUserSwitcher;
+        mMultiUserSwitch.setKeyguardUserSwitcher(keyguardUserSwitcher);
+    }
+
     @Override
     public boolean shouldDelayChildPressedState() {
         return true;
@@ -522,7 +607,6 @@
     }
 
     public void setKeyguardUserSwitcherShowing(boolean showing) {
-        // STOPSHIP: NOT CALLED PROPERLY WHEN GOING TO FULL SHADE AND RETURNING!?!
         mKeyguardUserSwitcherShowing = showing;
         updateVisibilities();
         updateSystemIconsLayoutParams();
@@ -553,8 +637,9 @@
         }
 
         public void update() {
-            final boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
-            mSystemIconsContainer.setClipBounds(onKeyguardAndCollapsed ? null : mClipBounds);
+            final boolean collapsedKeyguard = mKeyguardShowing && !mExpanded;
+            final boolean expanded = mExpanded && !mOverscrolled;
+            mSystemIconsContainer.setClipBounds(collapsedKeyguard || expanded ? null : mClipBounds);
         }
     }
 
@@ -599,7 +684,8 @@
 
         private void handleShowingDetail(final QSTile.DetailAdapter detail) {
             final boolean showingDetail = detail != null;
-            transition(mDateTime, !showingDetail);
+            transition(mClock, !showingDetail);
+            transition(mDateGroup, !showingDetail);
             transition(mQsDetailHeader, showingDetail);
             if (showingDetail) {
                 mQsDetailHeaderTitle.setText(detail.getTitle());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 93dcf90..af21f25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -176,6 +176,19 @@
     }
 
     public void setOccluded(boolean occluded) {
+        if (occluded && !mOccluded && mShowing) {
+            if (mPhoneStatusBar.isInLaunchTransition()) {
+                mOccluded = true;
+                mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
+                        new Runnable() {
+                            @Override
+                            public void run() {
+                                mStatusBarWindowManager.setKeyguardOccluded(true);
+                            }
+                        });
+                return;
+            }
+        }
         mOccluded = occluded;
         mStatusBarWindowManager.setKeyguardOccluded(occluded);
         reset();
@@ -188,29 +201,50 @@
     /**
      * Hides the keyguard view
      */
-    public void hide(long startTime, long fadeoutDuration) {
+    public void hide(long startTime, final long fadeoutDuration) {
         mShowing = false;
 
         long uptimeMillis = SystemClock.uptimeMillis();
-        long delay = startTime - uptimeMillis;
-        if (delay < 0) {
-            delay = 0;
+        long delay = Math.max(0, startTime - uptimeMillis);
+
+        if (mPhoneStatusBar.isInLaunchTransition() ) {
+            mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
+                @Override
+                public void run() {
+                    mStatusBarWindowManager.setKeyguardShowing(false);
+                    mStatusBarWindowManager.setKeyguardFadingAway(true);
+                    mBouncer.animateHide(PhoneStatusBar.FADE_KEYGUARD_START_DELAY,
+                            PhoneStatusBar.FADE_KEYGUARD_DURATION);
+                    updateStates();
+                    mScrimController.animateKeyguardFadingOut(
+                            PhoneStatusBar.FADE_KEYGUARD_START_DELAY,
+                            PhoneStatusBar.FADE_KEYGUARD_DURATION, null);
+                }
+            }, new Runnable() {
+                @Override
+                public void run() {
+                    mPhoneStatusBar.hideKeyguard();
+                    mStatusBarWindowManager.setKeyguardFadingAway(false);
+                    mViewMediatorCallback.keyguardGone();
+                }
+            });
+        } else {
+            mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
+            mPhoneStatusBar.hideKeyguard();
+            mStatusBarWindowManager.setKeyguardFadingAway(true);
+            mStatusBarWindowManager.setKeyguardShowing(false);
+            mBouncer.animateHide(delay, fadeoutDuration);
+            mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() {
+                @Override
+                public void run() {
+                    mStatusBarWindowManager.setKeyguardFadingAway(false);
+                    mPhoneStatusBar.finishKeyguardFadingAway();
+                }
+            });
+            mViewMediatorCallback.keyguardGone();
+            updateStates();
         }
 
-        mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
-        mPhoneStatusBar.hideKeyguard();
-        mStatusBarWindowManager.setKeyguardFadingAway(true);
-        mStatusBarWindowManager.setKeyguardShowing(false);
-        mBouncer.animateHide(delay, fadeoutDuration);
-        mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() {
-            @Override
-            public void run() {
-                mStatusBarWindowManager.setKeyguardFadingAway(false);
-                mPhoneStatusBar.finishKeyguardFadingAway();
-            }
-        });
-        mViewMediatorCallback.keyguardGone();
-        updateStates();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 7f27a0c..86a6622 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -29,12 +29,11 @@
 
     public SystemUIDialog(Context context) {
         super(context, R.style.Theme_SystemUI_Dialog);
-
         getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
-        attrs.setTitle("SystemUIDialog");
+        attrs.setTitle(getClass().getSimpleName());
         getWindow().setAttributes(attrs);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index e05e34b..36cfb86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -77,7 +77,7 @@
     public void initialize() {
         try {
             mCameraId = getCameraId();
-        } catch (CameraAccessException e) {
+        } catch (Throwable e) {
             Log.e(TAG, "Couldn't initialize.", e);
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index f3ff8ad..ac260db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -176,11 +176,9 @@
 
     @Override
     public void onAttachedToWindow() {
-        float densityScale = getResources().getDisplayMetrics().density;
         final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
-        float pagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
         float touchSlop = viewConfiguration.getScaledTouchSlop();
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
         mSwipeHelper.setMaxSwipeProgress(mMaxAlpha);
         mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index a3f3819..2be566c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -16,62 +16,56 @@
 
 package com.android.systemui.statusbar.policy;
 
-import com.android.systemui.BitmapHelper;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.StatusBarHeaderView;
 import com.android.systemui.statusbar.phone.UserAvatarView;
 
-import android.app.ActivityManagerNative;
 import android.content.Context;
-import android.content.pm.UserInfo;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.util.Log;
+import android.database.DataSetObserver;
+import android.provider.Settings;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
-import android.view.WindowManagerGlobal;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Manages the user switcher on the Keyguard.
  */
-public class KeyguardUserSwitcher implements View.OnClickListener {
+public class KeyguardUserSwitcher {
 
     private static final String TAG = "KeyguardUserSwitcher";
+    private static final boolean ALWAYS_ON = false;
+    private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
+            "lockscreenSimpleUserSwitcher";
 
-    private final Context mContext;
     private final ViewGroup mUserSwitcher;
-    private final UserManager mUserManager;
     private final StatusBarHeaderView mHeader;
+    private final Adapter mAdapter;
+    private final boolean mSimpleUserSwitcher;
 
     public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
-            StatusBarHeaderView header) {
-        mContext = context;
-        if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher)) {
+            StatusBarHeaderView header, UserSwitcherController userSwitcherController) {
+        if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) {
             mUserSwitcher = (ViewGroup) userSwitcher.inflate();
-            mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
             mHeader = header;
-            refresh();
+            mHeader.setKeyguarUserSwitcher(this);
+            mAdapter = new Adapter(context, userSwitcherController);
+            mAdapter.registerDataSetObserver(mDataSetObserver);
+            mSimpleUserSwitcher = Settings.Global.getInt(context.getContentResolver(),
+                    SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
         } else {
             mUserSwitcher = null;
-            mUserManager = null;
             mHeader = null;
+            mAdapter = null;
+            mSimpleUserSwitcher = false;
         }
     }
 
     public void setKeyguard(boolean keyguard) {
         if (mUserSwitcher != null) {
-            // TODO: Cache showUserSwitcherOnKeyguard().
-            if (keyguard && showUserSwitcherOnKeyguard()) {
+            if (keyguard && shouldExpandByDefault()) {
                 show();
-                refresh();
             } else {
                 hide();
             }
@@ -79,24 +73,11 @@
     }
 
     /**
-     * @return true if the user switcher should be shown on the lock screen.
+     * @return true if the user switcher should be expanded by default on the lock screen.
      * @see android.os.UserManager#isUserSwitcherEnabled()
      */
-    private boolean showUserSwitcherOnKeyguard() {
-        // TODO: Set isEdu. The edu provisioning process can add settings to Settings.Global.
-        boolean isEdu = false;
-        if (isEdu) {
-            return true;
-        }
-        List<UserInfo> users = mUserManager.getUsers(true /* excludeDying */);
-        int N = users.size();
-        int switchableUsers = 0;
-        for (int i = 0; i < N; i++) {
-            if (users.get(i).supportsSwitchTo()) {
-                switchableUsers++;
-            }
-        }
-        return switchableUsers > 1;
+    private boolean shouldExpandByDefault() {
+        return mSimpleUserSwitcher || mAdapter.getSwitchableUsers() > 1;
     }
 
     public void show() {
@@ -107,7 +88,7 @@
         }
     }
 
-    private void hide() {
+    public void hide() {
         if (mUserSwitcher != null) {
             // TODO: animate
             mUserSwitcher.setVisibility(View.GONE);
@@ -116,100 +97,76 @@
     }
 
     private void refresh() {
-        if (mUserSwitcher != null) {
-            new AsyncTask<Void, Void, ArrayList<UserData>>() {
-                @Override
-                protected ArrayList<UserData> doInBackground(Void... params) {
-                    return loadUsers();
-                }
-
-                @Override
-                protected void onPostExecute(ArrayList<UserData> userInfos) {
-                    bind(userInfos);
-                }
-            }.execute((Void[]) null);
-        }
-    }
-
-    private void bind(ArrayList<UserData> userList) {
-        mUserSwitcher.removeAllViews();
-        int N = userList.size();
+        final int childCount = mUserSwitcher.getChildCount();
+        final int adapterCount = mAdapter.getCount();
+        final int N = Math.max(childCount, adapterCount);
         for (int i = 0; i < N; i++) {
-            mUserSwitcher.addView(inflateUser(userList.get(i)));
-        }
-        // TODO: add Guest
-        // TODO: add (+) button
-    }
-
-    private View inflateUser(UserData user) {
-        View v = LayoutInflater.from(mUserSwitcher.getContext()).inflate(
-                R.layout.keyguard_user_switcher_item, mUserSwitcher, false);
-        TextView name = (TextView) v.findViewById(R.id.name);
-        UserAvatarView picture = (UserAvatarView) v.findViewById(R.id.picture);
-        name.setText(user.userInfo.name);
-        picture.setActivated(user.isCurrent);
-        if (user.userInfo.isGuest()) {
-            picture.setDrawable(mContext.getResources().getDrawable(R.drawable.ic_account_circle));
-        } else {
-            picture.setBitmap(user.userIcon);
-        }
-        v.setOnClickListener(this);
-        v.setTag(user.userInfo);
-        // TODO: mark which user is current for accessibility.
-        return v;
-    }
-
-    @Override
-    public void onClick(View v) {
-        switchUser(((UserInfo)v.getTag()).id);
-    }
-
-    // TODO: Factor out logic below and share with QS implementation.
-
-    private ArrayList<UserData> loadUsers() {
-        ArrayList<UserInfo> users = (ArrayList<UserInfo>) mUserManager
-                .getUsers(true /* excludeDying */);
-        int N = users.size();
-        ArrayList<UserData> result = new ArrayList<>(N);
-        int currentUser = -1;
-        try {
-            currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couln't get current user.", e);
-        }
-        final int avatarSize
-                = mContext.getResources().getDimensionPixelSize(R.dimen.max_avatar_size);
-        for (int i = 0; i < N; i++) {
-            UserInfo user = users.get(i);
-            if (user.supportsSwitchTo()) {
-                boolean isCurrent = user.id == currentUser;
-                final Bitmap picture = BitmapHelper.createCircularClip(
-                        mUserManager.getUserIcon(user.id),
-                        avatarSize, avatarSize);
-                result.add(new UserData(user, picture, isCurrent));
+            if (i < adapterCount) {
+                View oldView = null;
+                if (i < childCount) {
+                    oldView = mUserSwitcher.getChildAt(i);
+                }
+                View newView = mAdapter.getView(i, oldView, mUserSwitcher);
+                if (oldView == null) {
+                    // We ran out of existing views. Add it at the end.
+                    mUserSwitcher.addView(newView);
+                } else if (oldView != newView) {
+                    // We couldn't rebind the view. Replace it.
+                    mUserSwitcher.removeViewAt(i);
+                    mUserSwitcher.addView(newView, i);
+                }
+            } else {
+                int lastIndex = mUserSwitcher.getChildCount() - 1;
+                mUserSwitcher.removeViewAt(lastIndex);
             }
         }
-        return result;
     }
 
-    private void switchUser(int userId) {
-        try {
-            WindowManagerGlobal.getWindowManagerService().lockNow(null);
-            ActivityManagerNative.getDefault().switchUser(userId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't switch user.", e);
+    public final DataSetObserver mDataSetObserver = new DataSetObserver() {
+        @Override
+        public void onChanged() {
+            refresh();
         }
-    }
+    };
 
-    private static class UserData {
-        final UserInfo userInfo;
-        final Bitmap userIcon;
-        final boolean isCurrent;
+    public static class Adapter extends UserSwitcherController.BaseUserAdapter implements
+            View.OnClickListener {
 
-        UserData(UserInfo userInfo, Bitmap userIcon, boolean isCurrent) {
-            this.userInfo = userInfo;
-            this.userIcon = userIcon;
-            this.isCurrent = isCurrent;
+        private Context mContext;
+
+        public Adapter(Context context, UserSwitcherController controller) {
+            super(controller);
+            mContext = context;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            UserSwitcherController.UserRecord item = getItem(position);
+
+            if (convertView == null
+                    || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
+                convertView = LayoutInflater.from(mContext).inflate(
+                        R.layout.keyguard_user_switcher_item, parent, false);
+                convertView.setOnClickListener(this);
+            }
+
+            TextView nameView = (TextView) convertView.findViewById(R.id.name);
+            UserAvatarView pictureView = (UserAvatarView) convertView.findViewById(R.id.picture);
+
+            nameView.setText(getName(mContext, item));
+            if (item.picture == null) {
+                pictureView.setDrawable(mContext.getDrawable(R.drawable.ic_account_circle_qs));
+            } else {
+                pictureView.setBitmap(item.picture);
+            }
+            convertView.setActivated(item.isCurrent);
+            convertView.setTag(item);
+            return convertView;
+        }
+
+        @Override
+        public void onClick(View v) {
+            switchTo(((UserSwitcherController.UserRecord)v.getTag()));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 6d8b400..b64dcbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -24,7 +24,7 @@
     void setWifiEnabled(boolean enabled);
 
     public interface NetworkSignalChangedCallback {
-        void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+        void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId,
                 boolean activityIn, boolean activityOut,
                 String wifiSignalContentDescriptionId, String description);
         void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2b08902..4fc2e06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -401,7 +401,7 @@
         boolean wifiOut = wifiEnabled && mWifiSsid != null
                 && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
                 || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
-        cb.onWifiSignalChanged(mWifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
+        cb.onWifiSignalChanged(mWifiEnabled, mWifiConnected, mQSWifiIconId, wifiIn, wifiOut,
                 mContentDescriptionWifi, wifiDesc);
 
         boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
@@ -573,9 +573,11 @@
             switch(mServiceState.getVoiceRegState()) {
                 case ServiceState.STATE_POWER_OFF:
                     retVal = false;
+                    break;
                 case ServiceState.STATE_OUT_OF_SERVICE:
                 case ServiceState.STATE_EMERGENCY_ONLY:
                     retVal = mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
+                    break;
                 default:
                     retVal = true;
             }
@@ -597,8 +599,8 @@
 
     private final void updateTelephonySignalStrength() {
         Rlog.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService() + " ss=" + mSignalStrength);
-        if (false/*!hasService()*/) {
-            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
+        if (!hasService()) {
+            if (true/*CHATTY*/) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
             mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
             mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
             mDataSignalIconId = R.drawable.stat_sys_signal_null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
new file mode 100644
index 0000000..ca71521
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.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.systemui.statusbar.policy;
+
+import android.app.AlarmClockInfo;
+import android.app.AlarmManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserHandle;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+public class NextAlarmController extends BroadcastReceiver {
+
+    private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>();
+
+    private AlarmManager mAlarmManager;
+    private AlarmClockInfo mNextAlarm;
+
+    public NextAlarmController(Context context) {
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
+        context.registerReceiver(this, filter);
+        updateNextAlarm();
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("NextAlarmController state:");
+        pw.print("  mNextAlarm="); pw.println(mNextAlarm);
+    }
+
+    public void addStateChangedCallback(NextAlarmChangeCallback cb) {
+        mChangeCallbacks.add(cb);
+        cb.onNextAlarmChanged(mNextAlarm);
+    }
+
+    public void removeStateChangedCallback(NextAlarmChangeCallback cb) {
+        mChangeCallbacks.remove(cb);
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(Intent.ACTION_USER_SWITCHED)
+                || action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
+            updateNextAlarm();
+        }
+    }
+
+    private void updateNextAlarm() {
+        mNextAlarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
+        fireNextAlarmChanged();
+    }
+
+    private void fireNextAlarmChanged() {
+        int n = mChangeCallbacks.size();
+        for (int i = 0; i < n; i++) {
+            mChangeCallbacks.get(i).onNextAlarmChanged(mNextAlarm);
+        }
+    }
+
+    public interface NextAlarmChangeCallback {
+        void onNextAlarmChanged(AlarmClockInfo nextAlarm);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
new file mode 100644
index 0000000..d405172
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardActivityLauncher;
+import com.android.systemui.statusbar.phone.KeyguardPreviewContainer;
+
+import java.util.List;
+
+/**
+ * Utility class to inflate previews for phone and camera affordance.
+ */
+public class PreviewInflater {
+
+    private static final String TAG = "PreviewInflater";
+
+    private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout";
+
+    private Context mContext;
+    private LockPatternUtils mLockPatternUtils;
+
+    public PreviewInflater(Context context, LockPatternUtils lockPatternUtils) {
+        mContext = context;
+        mLockPatternUtils = lockPatternUtils;
+    }
+
+    public View inflatePreview(Intent intent) {
+        WidgetInfo info = getWidgetInfo(intent);
+        if (info == null) {
+            return null;
+        }
+        View v = inflateWidgetView(info);
+        if (v == null) {
+            return null;
+        }
+        KeyguardPreviewContainer container = new KeyguardPreviewContainer(mContext, null);
+        container.addView(v);
+        return container;
+    }
+
+    private View inflateWidgetView(WidgetInfo widgetInfo) {
+        View widgetView = null;
+        try {
+            Context appContext = mContext.createPackageContext(
+                    widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
+            LayoutInflater appInflater = (LayoutInflater)
+                    appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            appInflater = appInflater.cloneInContext(appContext);
+            widgetView = appInflater.inflate(widgetInfo.layoutId, null, false);
+        } catch (PackageManager.NameNotFoundException|RuntimeException e) {
+            Log.w(TAG, "Error creating widget view", e);
+        }
+        return widgetView;
+    }
+
+    private WidgetInfo getWidgetInfo(Intent intent) {
+        WidgetInfo info = new WidgetInfo();
+        PackageManager packageManager = mContext.getPackageManager();
+        final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
+                intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+        if (appList.size() == 0) {
+            return null;
+        }
+        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
+                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
+                mLockPatternUtils.getCurrentUser());
+        if (wouldLaunchResolverActivity(resolved, appList)) {
+            return null;
+        }
+        if (resolved == null || resolved.activityInfo == null) {
+            return null;
+        }
+        if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) {
+            return null;
+        }
+        int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
+        if (layoutId == 0) {
+            return null;
+        }
+        info.contextPackage = resolved.activityInfo.packageName;
+        info.layoutId = layoutId;
+        return info;
+    }
+
+    private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
+        // If the list contains the above resolved activity, then it can't be
+        // ResolverActivity itself.
+        for (int i = 0; i < appList.size(); i++) {
+            ResolveInfo tmp = appList.get(i);
+            if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
+                    && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static class WidgetInfo {
+        String contextPackage;
+        int layoutId;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 7bf2c34..7c00c7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -123,7 +123,7 @@
                     if (info.isGuest()) {
                         guestRecord = new UserRecord(info, null /* picture */,
                                 true /* isGuest */, isCurrent);
-                    } else if (!info.isManagedProfile()) {
+                    } else if (info.supportsSwitchTo()) {
                         Bitmap picture = bitmaps.get(info.id);
                         if (picture == null) {
                             picture = mUserManager.getUserIcon(info.id);
@@ -303,6 +303,18 @@
                 return item.info.name;
             }
         }
+
+        public int getSwitchableUsers() {
+            int result = 0;
+            ArrayList<UserRecord> users = mController.mUsers;
+            int N = users.size();
+            for (int i = 0; i < N; i++) {
+                if (users.get(i).info != null) {
+                    result++;
+                }
+            }
+            return result;
+        }
     }
 
     public static final class UserRecord {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 9bcffd1..9b819f2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -35,6 +35,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.SpeedBumpView;
@@ -139,6 +140,8 @@
     private boolean mExpandingNotification;
     private boolean mExpandedInThisMotion;
     private boolean mScrollingEnabled;
+    private DismissView mDismissView;
+    private boolean mDismissAllInProgress;
 
     /**
      * Was the scroller scrolled to the top when the down motion was observed?
@@ -161,7 +164,7 @@
      * motion.
      */
     private int mMaxScrollAfterExpand;
-    private OnLongClickListener mLongClickListener;
+    private SwipeHelper.LongPressListener mLongPressListener;
 
     /**
      * Should in this touch motion only be scrolling allowed? It's true when the scroller was
@@ -238,8 +241,8 @@
         mOverflingDistance = configuration.getScaledOverflingDistance();
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
-        mSwipeHelper.setLongPressListener(mLongClickListener);
+        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
+        mSwipeHelper.setLongPressListener(mLongPressListener);
 
         mSidePaddings = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_side_padding);
@@ -467,9 +470,9 @@
         return mBottomStackPeekSize;
     }
 
-    public void setLongPressListener(View.OnLongClickListener listener) {
+    public void setLongPressListener(SwipeHelper.LongPressListener listener) {
         mSwipeHelper.setLongPressListener(listener);
-        mLongClickListener = listener;
+        mLongPressListener = listener;
     }
 
     public void setScrollView(ViewGroup scrollView) {
@@ -481,6 +484,9 @@
     }
 
     public void onChildDismissed(View v) {
+        if (mDismissAllInProgress) {
+            return;
+        }
         if (DEBUG) Log.v(TAG, "onChildDismissed: " + v);
         final View veto = v.findViewById(R.id.veto);
         if (veto != null && veto.getVisibility() != View.GONE) {
@@ -627,8 +633,9 @@
         initView(getContext());
     }
 
-    public void dismissRowAnimated(View child, int vel) {
-        mSwipeHelper.dismissChild(child, vel);
+    public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
+        child.setClipBounds(null);
+        mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration);
     }
 
     @Override
@@ -1526,12 +1533,13 @@
      * @param newIndex the new index
      */
     public void changeViewPosition(View child, int newIndex) {
-        if (child != null && child.getParent() == this) {
+        int currentIndex = indexOfChild(child);
+        if (child != null && child.getParent() == this && currentIndex != newIndex) {
             mChangePositionInProgress = true;
             removeView(child);
             addView(child, newIndex);
             mChangePositionInProgress = false;
-            if (mIsExpanded && mAnimationsEnabled) {
+            if (mIsExpanded && mAnimationsEnabled && child.getVisibility() != View.GONE) {
                 mChildrenChangingPositions.add(child);
                 mNeedsAnimation = true;
             }
@@ -1918,7 +1926,8 @@
     }
 
     public void goToFullShade() {
-        updateSpeedBump(true);
+        updateSpeedBump(true /* visibility */);
+        mDismissView.setInvisible();
     }
 
     public void cancelExpandHelper() {
@@ -1962,6 +1971,54 @@
         requestChildrenUpdate();
     }
 
+    public void setDismissView(DismissView dismissView) {
+        mDismissView = dismissView;
+        addView(mDismissView);
+    }
+
+    public void updateDismissView(boolean visible) {
+        int oldVisibility = mDismissView.willBeGone() ? GONE : mDismissView.getVisibility();
+        int newVisibility = visible ? VISIBLE : GONE;
+        if (oldVisibility != newVisibility) {
+            if (oldVisibility == GONE) {
+                if (mDismissView.willBeGone()) {
+                    mDismissView.cancelAnimation();
+                } else {
+                    mDismissView.setInvisible();
+                    mDismissView.setVisibility(newVisibility);
+                }
+                mDismissView.setWillBeGone(false);
+                updateContentHeight();
+            } else {
+                mDismissView.setWillBeGone(true);
+                mDismissView.performVisibilityAnimation(false, new Runnable() {
+                    @Override
+                    public void run() {
+                        mDismissView.setVisibility(GONE);
+                        mDismissView.setWillBeGone(false);
+                        updateContentHeight();
+                    }
+                });
+            }
+        }
+    }
+
+    public void setDismissAllInProgress(boolean dismissAllInProgress) {
+        mDismissAllInProgress = dismissAllInProgress;
+    }
+
+    public boolean isDismissViewNotGone() {
+        return mDismissView.getVisibility() != View.GONE && !mDismissView.willBeGone();
+    }
+
+    public boolean isDismissViewVisible() {
+        return mDismissView.isVisible();
+    }
+
+    public int getDismissViewHeight() {
+        return mDismissView.getHeight() + mPaddingBetweenElementsNormal;
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index f48739c..7b90a351 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -21,6 +21,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.systemui.R;
+import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.SpeedBumpView;
 
@@ -38,10 +40,13 @@
     private final ViewGroup mHostView;
     private Map<ExpandableView, ViewState> mStateMap;
     private final Rect mClipRect = new Rect();
+    private final int mClearAllTopPadding;
 
     public StackScrollState(ViewGroup hostView) {
         mHostView = hostView;
         mStateMap = new HashMap<ExpandableView, ViewState>();
+        mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize(
+                R.dimen.clear_all_padding_top);
     }
 
     public ViewGroup getHostView() {
@@ -90,6 +95,7 @@
             if (!state.gone) {
                 float alpha = child.getAlpha();
                 float yTranslation = child.getTranslationY();
+                float xTranslation = child.getTranslationX();
                 float zTranslation = child.getTranslationZ();
                 float scale = child.getScaleX();
                 int height = child.getActualHeight();
@@ -99,7 +105,7 @@
                 float newScale = state.scale;
                 int newHeight = state.height;
                 boolean becomesInvisible = newAlpha == 0.0f;
-                if (alpha != newAlpha) {
+                if (alpha != newAlpha && xTranslation == 0) {
                     // apply layer type
                     boolean becomesFullyVisible = newAlpha == 1.0f;
                     boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible;
@@ -167,6 +173,10 @@
                 if(child instanceof SpeedBumpView) {
                     float lineEnd = newYTranslation + newHeight / 2;
                     performSpeedBumpAnimation(i, (SpeedBumpView) child, lineEnd);
+                } else if (child instanceof DismissView) {
+                    DismissView dismissView = (DismissView) child;
+                    boolean visible = state.topOverLap < mClearAllTopPadding;
+                    dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 0c84675..71524ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -159,7 +159,7 @@
         }
 
         // start alpha animation
-        if (alphaChanging) {
+        if (alphaChanging && child.getTranslationX() == 0) {
             startAlphaAnimation(child, viewState, delay);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index d0f61f0..a123bf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -95,6 +95,10 @@
     public void setWindowState(int window, int state) {
     }
 
+    @Override // CommandQueue
+    public void buzzBeepBlinked() {
+    }
+
     @Override
     protected WindowManager.LayoutParams getSearchLayoutParams(
             LayoutParams layoutParams) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 9ba9745..149d09a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -58,6 +58,7 @@
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
 import com.android.internal.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.io.FileDescriptor;
@@ -89,6 +90,7 @@
     private static final int TIMEOUT_DELAY = 3000;
     private static final int TIMEOUT_DELAY_SHORT = 1500;
     private static final int TIMEOUT_DELAY_COLLAPSED = 4500;
+    private static final int TIMEOUT_DELAY_SAFETY_WARNING = 5000;
     private static final int TIMEOUT_DELAY_EXPANDED = 10000;
 
     private static final int MSG_VOLUME_CHANGED = 0;
@@ -238,42 +240,61 @@
     private ToneGenerator mToneGenerators[];
     private Vibrator mVibrator;
 
-    private static AlertDialog sConfirmSafeVolumeDialog;
-    private static Object sConfirmSafeVolumeLock = new Object();
+    private static AlertDialog sSafetyWarning;
+    private static Object sSafetyWarningLock = new Object();
 
-    private static class WarningDialogReceiver extends BroadcastReceiver
-            implements DialogInterface.OnDismissListener {
+    private static class SafetyWarning extends SystemUIDialog
+            implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
         private final Context mContext;
-        private final Dialog mDialog;
         private final VolumePanel mVolumePanel;
+        private final AudioManager mAudioManager;
 
-        WarningDialogReceiver(Context context, Dialog dialog, VolumePanel volumePanel) {
+        SafetyWarning(Context context, VolumePanel volumePanel, AudioManager audioManager) {
+            super(context);
             mContext = context;
-            mDialog = dialog;
             mVolumePanel = volumePanel;
+            mAudioManager = audioManager;
+
+            setMessage(mContext.getString(com.android.internal.R.string.safe_media_volume_warning));
+            setButton(DialogInterface.BUTTON_POSITIVE,
+                    mContext.getString(com.android.internal.R.string.yes), this);
+            setButton(DialogInterface.BUTTON_NEGATIVE,
+                    mContext.getString(com.android.internal.R.string.no), (OnClickListener) null);
+            setOnDismissListener(this);
+
             IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-            context.registerReceiver(this, filter);
+            context.registerReceiver(mReceiver, filter);
         }
 
         @Override
-        public void onReceive(Context context, Intent intent) {
-            mDialog.cancel();
-            cleanUp();
+        public void onClick(DialogInterface dialog, int which) {
+            mAudioManager.disableSafeMediaVolume();
         }
 
         @Override
         public void onDismiss(DialogInterface unused) {
-            mContext.unregisterReceiver(this);
+            mContext.unregisterReceiver(mReceiver);
             cleanUp();
         }
 
         private void cleanUp() {
-            synchronized (sConfirmSafeVolumeLock) {
-                sConfirmSafeVolumeDialog = null;
+            synchronized (sSafetyWarningLock) {
+                sSafetyWarning = null;
             }
             mVolumePanel.forceTimeout(0);
             mVolumePanel.updateStates();
         }
+
+        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                    if (LOGD) Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
+                    cancel();
+                    cleanUp();
+                }
+            }
+        };
     }
 
     public VolumePanel(Context context, ZenModeController zenController) {
@@ -305,7 +326,7 @@
             @Override
             public boolean onTouchEvent(MotionEvent event) {
                 if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
-                        sConfirmSafeVolumeDialog == null) {
+                        sSafetyWarning == null) {
                     forceTimeout(0);
                     return true;
                 }
@@ -371,7 +392,7 @@
         final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
         mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
 
-        listenToRingerMode();
+        registerReceiver();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -389,7 +410,7 @@
         pw.print("  isShowing()="); pw.println(isShowing());
         pw.print("  mCallback="); pw.println(mCallback);
         pw.print("  sConfirmSafeVolumeDialog=");
-        pw.println(sConfirmSafeVolumeDialog != null ? "<not null>" : null);
+        pw.println(sSafetyWarning != null ? "<not null>" : null);
         pw.print("  mActiveStreamType="); pw.println(mActiveStreamType);
         pw.print("  mStreamControls=");
         if (mStreamControls == null) {
@@ -441,9 +462,10 @@
         updateStates();
     }
 
-    private void listenToRingerMode() {
+    private void registerReceiver() {
         final IntentFilter filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -453,6 +475,10 @@
                     removeMessages(MSG_RINGER_MODE_CHANGED);
                     sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED));
                 }
+
+                if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+                    postDismiss(0);
+                }
             }
         }, filter);
     }
@@ -635,7 +661,7 @@
             sc.seekbarView.setEnabled(!fixedVolume);
         } else if (fixedVolume ||
                         (sc.streamType != mAudioManager.getMasterStreamType() && muted) ||
-                        (sConfirmSafeVolumeDialog != null)) {
+                        (sSafetyWarning != null)) {
             sc.seekbarView.setEnabled(false);
         } else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
             sc.seekbarView.setEnabled(false);
@@ -682,7 +708,8 @@
     }
 
     private void updateTimeoutDelay() {
-        mTimeoutDelay = mActiveStreamType == AudioManager.STREAM_MUSIC ? TIMEOUT_DELAY_SHORT
+        mTimeoutDelay = sSafetyWarning != null ? TIMEOUT_DELAY_SAFETY_WARNING
+                : mActiveStreamType == AudioManager.STREAM_MUSIC ? TIMEOUT_DELAY_SHORT
                 : mZenPanelExpanded ? TIMEOUT_DELAY_EXPANDED
                 : isZenPanelVisible() ? TIMEOUT_DELAY_COLLAPSED
                 : TIMEOUT_DELAY;
@@ -1100,30 +1127,14 @@
     }
 
     protected void onDisplaySafeVolumeWarning(int flags) {
-        if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || isShowing()) {
-            synchronized (sConfirmSafeVolumeLock) {
-                if (sConfirmSafeVolumeDialog != null) {
+        if ((flags & (AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_SHOW_UI_WARNINGS)) != 0
+                || isShowing()) {
+            synchronized (sSafetyWarningLock) {
+                if (sSafetyWarning != null) {
                     return;
                 }
-                sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
-                        .setMessage(com.android.internal.R.string.safe_media_volume_warning)
-                        .setPositiveButton(com.android.internal.R.string.yes,
-                                            new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                mAudioManager.disableSafeMediaVolume();
-                            }
-                        })
-                        .setNegativeButton(com.android.internal.R.string.no, null)
-                        .setIconAttribute(android.R.attr.alertDialogIcon)
-                        .create();
-                final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
-                        sConfirmSafeVolumeDialog, this);
-
-                sConfirmSafeVolumeDialog.setOnDismissListener(warning);
-                sConfirmSafeVolumeDialog.getWindow().setType(
-                                                WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-                sConfirmSafeVolumeDialog.show();
+                sSafetyWarning = new SafetyWarning(mContext, this, mAudioManager);
+                sSafetyWarning.show();
             }
             updateStates();
         }
@@ -1227,9 +1238,10 @@
                         mCallback.onVisible(false);
                     }
                 }
-                synchronized (sConfirmSafeVolumeLock) {
-                    if (sConfirmSafeVolumeDialog != null) {
-                        sConfirmSafeVolumeDialog.dismiss();
+                synchronized (sSafetyWarningLock) {
+                    if (sSafetyWarning != null) {
+                        if (LOGD) Log.d(mTag, "SafetyWarning timeout");
+                        sSafetyWarning.dismiss();
                     }
                 }
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 9d050f9..cc351f9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -195,7 +195,7 @@
         @Override
         public void remoteVolumeChanged(ISessionController binder, int flags)
                 throws RemoteException {
-            MediaController controller = new MediaController(binder);
+            MediaController controller = new MediaController(mContext, binder);
             mPanel.postRemoteVolumeChanged(controller, flags);
         }
 
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 5c8a8ef8..57b0731 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -133,6 +133,14 @@
         setCropViewTileSource(bitmapSource, true, false, onLoad);
     }
 
+    @Override
+    protected void onDestroy() {
+        if (mCropView != null) {
+            mCropView.destroy();
+        }
+        super.onDestroy();
+    }
+
     public void setCropViewTileSource(
             final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled,
             final boolean moveToLeft, final Runnable postExecute) {
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
index a4c2ddd..8fc4647 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
@@ -293,7 +293,6 @@
 
         @Override
         public boolean onTouchEvent(MotionEvent motion) {
-            Slog.v(TAG, "ClingWindowView.onTouchEvent");
             return true;
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index e3c2203..3e75947 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -211,6 +211,9 @@
 
     private float mElevation;
 
+    /** Whether window content should be clipped to the background outline. */
+    private boolean mClipToOutline;
+
     private int mFrameResource = 0;
 
     private int mTextColor = 0;
@@ -1173,7 +1176,7 @@
                 mDecorContentParent != null) {
             final TypedValue outValue = new TypedValue();
             final Theme baseTheme = context.getTheme();
-            baseTheme.resolveAttribute(com.android.internal.R.attr.actionBarTheme, outValue, true);
+            baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
 
             Theme widgetTheme = null;
             if (outValue.resourceId != 0) {
@@ -1181,10 +1184,10 @@
                 widgetTheme.setTo(baseTheme);
                 widgetTheme.applyStyle(outValue.resourceId, true);
                 widgetTheme.resolveAttribute(
-                        com.android.internal.R.attr.actionBarWidgetTheme, outValue, true);
+                        R.attr.actionBarWidgetTheme, outValue, true);
             } else {
                 baseTheme.resolveAttribute(
-                        com.android.internal.R.attr.actionBarWidgetTheme, outValue, true);
+                        R.attr.actionBarWidgetTheme, outValue, true);
             }
 
             if (outValue.resourceId != 0) {
@@ -1305,6 +1308,7 @@
             mBackgroundDrawable = drawable;
             if (mDecor != null) {
                 mDecor.setWindowBackground(drawable);
+                mDecor.setClipToOutline(drawable != null && mClipToOutline);
             }
         }
     }
@@ -1428,7 +1432,7 @@
         if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
             updateProgressBars(value);
         } else if (featureId == FEATURE_CUSTOM_TITLE) {
-            FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container);
+            FrameLayout titleContainer = (FrameLayout) findViewById(R.id.title_container);
             if (titleContainer != null) {
                 mLayoutInflater.inflate(value, titleContainer);
             }
@@ -1546,7 +1550,7 @@
 
     private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
         final int features = getLocalFeatures();
-        Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out);
+        Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.fade_out);
         anim.setDuration(1000);
         if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
                 spinnyProgressBar != null &&
@@ -2440,7 +2444,7 @@
                             && getAttributes().height
                             == WindowManager.LayoutParams.MATCH_PARENT) {
                         mMenuBackground = getContext().getDrawable(
-                                com.android.internal.R.drawable.menu_background);
+                                R.drawable.menu_background);
                     }
                     if (mMenuBackground != null) {
                         mMenuBackground.setBounds(drawingBounds.left,
@@ -2606,7 +2610,7 @@
                     if (isFloating()) {
                         mActionModeView = new ActionBarContextView(mContext);
                         mActionModePopup = new PopupWindow(mContext, null,
-                                com.android.internal.R.attr.actionModePopupWindowStyle);
+                                R.attr.actionModePopupWindowStyle);
                         mActionModePopup.setWindowLayoutType(
                                 WindowManager.LayoutParams.TYPE_APPLICATION);
                         mActionModePopup.setContentView(mActionModeView);
@@ -2614,7 +2618,7 @@
 
                         TypedValue heightValue = new TypedValue();
                         mContext.getTheme().resolveAttribute(
-                                com.android.internal.R.attr.actionBarSize, heightValue, true);
+                                R.attr.actionBarSize, heightValue, true);
                         final int height = TypedValue.complexToDimensionPixelSize(heightValue.data,
                                 mContext.getResources().getDisplayMetrics());
                         mActionModeView.setContentHeight(height);
@@ -2628,7 +2632,7 @@
                         };
                     } else {
                         ViewStub stub = (ViewStub) findViewById(
-                                com.android.internal.R.id.action_mode_bar_stub);
+                                R.id.action_mode_bar_stub);
                         if (stub != null) {
                             mActionModeView = (ActionBarContextView) stub.inflate();
                         }
@@ -3093,14 +3097,14 @@
         if (false) {
             System.out.println("From style:");
             String s = "Attrs:";
-            for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) {
-                s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="
+            for (int i = 0; i < R.styleable.Window.length; i++) {
+                s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
                         + a.getString(i);
             }
             System.out.println(s);
         }
 
-        mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
+        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
         int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                 & (~getForcedWindowFlags());
         if (mIsFloating) {
@@ -3110,78 +3114,78 @@
             setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
+        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
             requestFeature(FEATURE_NO_TITLE);
-        } else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) {
+        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
             // Don't allow an action bar if there is no title.
             requestFeature(FEATURE_ACTION_BAR);
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) {
+        if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
             requestFeature(FEATURE_ACTION_BAR_OVERLAY);
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionModeOverlay, false)) {
+        if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
             requestFeature(FEATURE_ACTION_MODE_OVERLAY);
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowSwipeToDismiss, false)) {
+        if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
             requestFeature(FEATURE_SWIPE_TO_DISMISS);
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
+        if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
             setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowTranslucentStatus,
+        if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
                 false)) {
             setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
                     & (~getForcedWindowFlags()));
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowTranslucentNavigation,
+        if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
                 false)) {
             setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
                     & (~getForcedWindowFlags()));
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowOverscan, false)) {
+        if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
             setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
+        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
             setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowEnableSplitTouch,
+        if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch,
                 getContext().getApplicationInfo().targetSdkVersion
                         >= android.os.Build.VERSION_CODES.HONEYCOMB)) {
             setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));
         }
 
-        a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
-        a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
-        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor)) {
+        a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
+        a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
+        if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
             if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
-            a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor,
+            a.getValue(R.styleable.Window_windowFixedWidthMajor,
                     mFixedWidthMajor);
         }
-        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor)) {
+        if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
             if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
-            a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor,
+            a.getValue(R.styleable.Window_windowFixedWidthMinor,
                     mFixedWidthMinor);
         }
-        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor)) {
+        if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
             if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
-            a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor,
+            a.getValue(R.styleable.Window_windowFixedHeightMajor,
                     mFixedHeightMajor);
         }
-        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor)) {
+        if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
             if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
-            a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor,
+            a.getValue(R.styleable.Window_windowFixedHeightMinor,
                     mFixedHeightMinor);
         }
-        if (a.getBoolean(com.android.internal.R.styleable.Window_windowContentTransitions, false)) {
+        if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {
             requestFeature(FEATURE_CONTENT_TRANSITIONS);
         }
 
@@ -3190,9 +3194,9 @@
         if (windowService != null) {
             final Display display = windowService.getDefaultDisplay();
             if (display.getDisplayId() == Display.DEFAULT_DISPLAY &&
-                    a.hasValue(com.android.internal.R.styleable.Window_windowOutsetBottom)) {
+                    a.hasValue(R.styleable.Window_windowOutsetBottom)) {
                 if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
-                a.getValue(com.android.internal.R.styleable.Window_windowOutsetBottom,
+                a.getValue(R.styleable.Window_windowOutsetBottom,
                         mOutsetBottom);
             }
         }
@@ -3203,7 +3207,7 @@
         final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
         final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.L;
         final boolean targetHcNeedsOptions = context.getResources().getBoolean(
-                com.android.internal.R.bool.target_honeycomb_needs_options_menu);
+                R.bool.target_honeycomb_needs_options_menu);
         final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
 
         if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
@@ -3216,7 +3220,7 @@
         // therefore must know about visibility changes of those.
         if (!mIsFloating && ActivityManager.isHighEndGfx()) {
             if (!targetPreL && a.getBoolean(
-                    com.android.internal.R.styleable.Window_windowDrawsSystemBarBackgrounds,
+                    R.styleable.Window_windowDrawsSystemBarBackgrounds,
                     false)) {
                 setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                         FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
@@ -3233,7 +3237,7 @@
         if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
                 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
             if (a.getBoolean(
-                    com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
+                    R.styleable.Window_windowCloseOnTouchOutside,
                     false)) {
                 setCloseOnTouchOutsideIfNotSet(true);
             }
@@ -3243,11 +3247,11 @@
 
         if (!hasSoftInputMode()) {
             params.softInputMode = a.getInt(
-                    com.android.internal.R.styleable.Window_windowSoftInputMode,
+                    R.styleable.Window_windowSoftInputMode,
                     params.softInputMode);
         }
 
-        if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled,
+        if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
                 mIsFloating)) {
             /* All dialogs should have the window dimmed */
             if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
@@ -3261,7 +3265,7 @@
 
         if (params.windowAnimations == 0) {
             params.windowAnimations = a.getResourceId(
-                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+                    R.styleable.Window_windowAnimationStyle, 0);
         }
 
         // The rest are only done if this window is not embedded; otherwise,
@@ -3270,10 +3274,10 @@
             if (mBackgroundDrawable == null) {
                 if (mBackgroundResource == 0) {
                     mBackgroundResource = a.getResourceId(
-                            com.android.internal.R.styleable.Window_windowBackground, 0);
+                            R.styleable.Window_windowBackground, 0);
                 }
                 if (mFrameResource == 0) {
-                    mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);
+                    mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
                 }
                 if (false) {
                     System.out.println("Background: "
@@ -3281,8 +3285,9 @@
                             + Integer.toHexString(mFrameResource));
                 }
             }
-            mElevation = a.getDimension(com.android.internal.R.styleable.Window_windowElevation, 0);
-            mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);
+            mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
+            mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
+            mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
         }
 
         // Inflate the window decor.
@@ -3291,15 +3296,15 @@
         int features = getLocalFeatures();
         // System.out.println("Features: 0x" + Integer.toHexString(features));
         if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
-            layoutResource = com.android.internal.R.layout.screen_swipe_dismiss;
+            layoutResource = R.layout.screen_swipe_dismiss;
         } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
             if (mIsFloating) {
                 TypedValue res = new TypedValue();
                 getContext().getTheme().resolveAttribute(
-                        com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);
+                        R.attr.dialogTitleIconsDecorLayout, res, true);
                 layoutResource = res.resourceId;
             } else {
-                layoutResource = com.android.internal.R.layout.screen_title_icons;
+                layoutResource = R.layout.screen_title_icons;
             }
             // XXX Remove this once action bar supports these features.
             removeFeature(FEATURE_ACTION_BAR);
@@ -3308,7 +3313,7 @@
                 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
             // Special case for a window with only a progress bar (and title).
             // XXX Need to have a no-title version of embedded windows.
-            layoutResource = com.android.internal.R.layout.screen_progress;
+            layoutResource = R.layout.screen_progress;
             // System.out.println("Progress!");
         } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
             // Special case for a window with a custom title.
@@ -3316,10 +3321,10 @@
             if (mIsFloating) {
                 TypedValue res = new TypedValue();
                 getContext().getTheme().resolveAttribute(
-                        com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true);
+                        R.attr.dialogCustomTitleDecorLayout, res, true);
                 layoutResource = res.resourceId;
             } else {
-                layoutResource = com.android.internal.R.layout.screen_custom_title;
+                layoutResource = R.layout.screen_custom_title;
             }
             // XXX Remove this once action bar supports these features.
             removeFeature(FEATURE_ACTION_BAR);
@@ -3329,21 +3334,21 @@
             if (mIsFloating) {
                 TypedValue res = new TypedValue();
                 getContext().getTheme().resolveAttribute(
-                        com.android.internal.R.attr.dialogTitleDecorLayout, res, true);
+                        R.attr.dialogTitleDecorLayout, res, true);
                 layoutResource = res.resourceId;
             } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
                 layoutResource = a.getResourceId(
-                        com.android.internal.R.styleable.Window_windowActionBarFullscreenDecorLayout,
-                        com.android.internal.R.layout.screen_action_bar);
+                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
+                        R.layout.screen_action_bar);
             } else {
-                layoutResource = com.android.internal.R.layout.screen_title;
+                layoutResource = R.layout.screen_title;
             }
             // System.out.println("Title!");
         } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
-            layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;
+            layoutResource = R.layout.screen_simple_overlay_action_mode;
         } else {
             // Embedded, so no decoration is needed.
-            layoutResource = com.android.internal.R.layout.screen_simple;
+            layoutResource = R.layout.screen_simple;
             // System.out.println("Simple!");
         }
 
@@ -3379,6 +3384,10 @@
             }
             mDecor.setWindowBackground(background);
 
+            if (background != null) {
+                mDecor.setClipToOutline(mClipToOutline);
+            }
+
             final Drawable frame;
             if (mFrameResource != 0) {
                 frame = getContext().getDrawable(mFrameResource);
@@ -3425,7 +3434,7 @@
             mDecor.makeOptionalFitsSystemWindows();
 
             final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
-                    com.android.internal.R.id.decor_content_parent);
+                    R.id.decor_content_parent);
 
             if (decorContentParent != null) {
                 mDecorContentParent = decorContentParent;
@@ -3469,12 +3478,12 @@
                     }
                 });
             } else {
-                mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
+                mTitleView = (TextView)findViewById(R.id.title);
                 if (mTitleView != null) {
                     mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
                     if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                         View titleContainer = findViewById(
-                                com.android.internal.R.id.title_container);
+                                R.id.title_container);
                         if (titleContainer != null) {
                             titleContainer.setVisibility(View.GONE);
                         } else {
@@ -3494,7 +3503,7 @@
             if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                 if (mTransitionManager == null) {
                     final int transitionRes = getWindowStyle().getResourceId(
-                            com.android.internal.R.styleable.Window_windowContentTransitionManager,
+                            R.styleable.Window_windowContentTransitionManager,
                             0);
                     if (transitionRes != 0) {
                         final TransitionInflater inflater = TransitionInflater.from(getContext());
@@ -3506,26 +3515,26 @@
                 }
 
                 mEnterTransition = getTransition(mEnterTransition,
-                        com.android.internal.R.styleable.Window_windowEnterTransition);
+                        R.styleable.Window_windowEnterTransition);
                 mExitTransition = getTransition(mExitTransition,
-                        com.android.internal.R.styleable.Window_windowExitTransition);
+                        R.styleable.Window_windowExitTransition);
                 mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition,
-                        com.android.internal.R.styleable.Window_windowSharedElementEnterTransition);
+                        R.styleable.Window_windowSharedElementEnterTransition);
                 mSharedElementExitTransition = getTransition(mSharedElementExitTransition,
-                        com.android.internal.R.styleable.Window_windowSharedElementExitTransition);
+                        R.styleable.Window_windowSharedElementExitTransition);
                 if (mAllowEnterTransitionOverlap == null) {
                     mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
-                            com.android.internal.R.styleable.
+                            R.styleable.
                                     Window_windowAllowEnterTransitionOverlap, true);
                 }
                 if (mAllowExitTransitionOverlap == null) {
                     mAllowExitTransitionOverlap = getWindowStyle().getBoolean(
-                            com.android.internal.R.styleable.
+                            R.styleable.
                                     Window_windowAllowExitTransitionOverlap, true);
                 }
                 if (mBackgroundFadeDurationMillis < 0) {
                     mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
-                            com.android.internal.R.styleable.
+                            R.styleable.
                                     Window_windowTransitionBackgroundFadeDuration,
                             DEFAULT_BACKGROUND_FADE_DURATION_MS);
                 }
@@ -3539,7 +3548,7 @@
         }
         int transitionId = getWindowStyle().getResourceId(id, -1);
         Transition transition = null;
-        if (transitionId != -1 && transitionId != com.android.internal.R.transition.no_transition) {
+        if (transitionId != -1 && transitionId != R.transition.no_transition) {
             TransitionInflater inflater = TransitionInflater.from(getContext());
             transition = inflater.inflateTransition(transitionId);
         }
@@ -3713,7 +3722,7 @@
         if (mContentParent == null) {
             installDecor();
         }
-        return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon));
+        return (mLeftIconView = (ImageView)findViewById(R.id.left_icon));
     }
 
     @Override
@@ -3731,7 +3740,7 @@
         if (mContentParent == null && shouldInstallDecor) {
             installDecor();
         }
-        mCircularProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_circular);
+        mCircularProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
         if (mCircularProgressBar != null) {
             mCircularProgressBar.setVisibility(View.INVISIBLE);
         }
@@ -3745,7 +3754,7 @@
         if (mContentParent == null && shouldInstallDecor) {
             installDecor();
         }
-        mHorizontalProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_horizontal);
+        mHorizontalProgressBar = (ProgressBar) findViewById(R.id.progress_horizontal);
         if (mHorizontalProgressBar != null) {
             mHorizontalProgressBar.setVisibility(View.INVISIBLE);
         }
@@ -3759,12 +3768,12 @@
         if (mContentParent == null) {
             installDecor();
         }
-        return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon));
+        return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
     }
 
     private void registerSwipeCallbacks() {
         SwipeDismissLayout swipeDismiss =
-                (SwipeDismissLayout) findViewById(com.android.internal.R.id.content);
+                (SwipeDismissLayout) findViewById(R.id.content);
         swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
             @Override
             public void onDismissed(SwipeDismissLayout layout) {
@@ -3882,7 +3891,7 @@
     private boolean isTranslucent() {
         TypedArray a = getWindowStyle();
         return a.getBoolean(a.getResourceId(
-                com.android.internal.R.styleable.Window_windowIsTranslucent, 0), false);
+                R.styleable.Window_windowIsTranslucent, 0), false);
     }
 
     @Override
@@ -4100,18 +4109,18 @@
         }
 
         void setStyle(Context context) {
-            TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+            TypedArray a = context.obtainStyledAttributes(R.styleable.Theme);
             background = a.getResourceId(
-                    com.android.internal.R.styleable.Theme_panelBackground, 0);
+                    R.styleable.Theme_panelBackground, 0);
             fullBackground = a.getResourceId(
-                    com.android.internal.R.styleable.Theme_panelFullBackground, 0);
+                    R.styleable.Theme_panelFullBackground, 0);
             windowAnimations = a.getResourceId(
-                    com.android.internal.R.styleable.Theme_windowAnimationStyle, 0);
+                    R.styleable.Theme_windowAnimationStyle, 0);
             isCompact = a.getBoolean(
-                    com.android.internal.R.styleable.Theme_panelMenuIsCompact, false);
+                    R.styleable.Theme_panelMenuIsCompact, false);
             listPresenterTheme = a.getResourceId(
-                    com.android.internal.R.styleable.Theme_panelMenuListTheme,
-                    com.android.internal.R.style.Theme_ExpandedMenu);
+                    R.styleable.Theme_panelMenuListTheme,
+                    R.style.Theme_ExpandedMenu);
             a.recycle();
         }
 
@@ -4138,9 +4147,9 @@
 
             if (listMenuPresenter == null) {
                 listMenuPresenter = new ListMenuPresenter(
-                        com.android.internal.R.layout.list_menu_item_layout, listPresenterTheme);
+                        R.layout.list_menu_item_layout, listPresenterTheme);
                 listMenuPresenter.setCallback(cb);
-                listMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter);
+                listMenuPresenter.setId(R.id.list_menu_presenter);
                 menu.addMenuPresenter(listMenuPresenter);
             }
 
@@ -4159,7 +4168,7 @@
             if (iconMenuPresenter == null) {
                 iconMenuPresenter = new IconMenuPresenter(context);
                 iconMenuPresenter.setCallback(cb);
-                iconMenuPresenter.setId(com.android.internal.R.id.icon_menu_presenter);
+                iconMenuPresenter.setId(R.id.icon_menu_presenter);
                 menu.addMenuPresenter(iconMenuPresenter);
             }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 71f1d211..324f536 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2339,8 +2339,8 @@
                 Settings.System.putIntForUser(mContext.getContentResolver(),
                         Settings.System.SCREEN_BRIGHTNESS, brightness,
                         UserHandle.USER_CURRENT_OR_SELF);
-                Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
-                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF);
+                mContext.startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
+                        UserHandle.CURRENT_OR_SELF);
             }
             return -1;
         } else if (keyCode == KeyEvent.KEYCODE_META_LEFT) {
@@ -5401,7 +5401,7 @@
         }
         final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
-        if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotOccluded())) {
+        if (hapticsDisabled && !always) {
             return false;
         }
         long[] pattern = null;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 07bb713..b1f1954 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -62,7 +62,6 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
-import android.util.LongArray;
 import android.util.Pools.Pool;
 import android.util.Pools.SimplePool;
 import android.util.Slog;
@@ -114,8 +113,6 @@
  * accessed only by the system. The task of this service is to be a centralized
  * event dispatch for {@link AccessibilityEvent}s generated across all processes
  * on the device. Events are dispatched to {@link AccessibilityService}s.
- *
- * @hide
  */
 public class AccessibilityManagerService extends IAccessibilityManager.Stub {
 
@@ -155,13 +152,13 @@
     private final Object mLock = new Object();
 
     private final Pool<PendingEvent> mPendingEventPool =
-            new SimplePool<PendingEvent>(MAX_POOL_SIZE);
+            new SimplePool<>(MAX_POOL_SIZE);
 
     private final SimpleStringSplitter mStringColonSplitter =
             new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
 
     private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
-            new ArrayList<AccessibilityServiceInfo>();
+            new ArrayList<>();
 
     private final Rect mTempRect = new Rect();
 
@@ -183,27 +180,25 @@
 
     private boolean mHasInputFilter;
 
-    private final Set<ComponentName> mTempComponentNameSet = new HashSet<ComponentName>();
+    private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();
 
     private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
-            new ArrayList<AccessibilityServiceInfo>();
+            new ArrayList<>();
 
     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
-            new RemoteCallbackList<IAccessibilityManagerClient>();
+            new RemoteCallbackList<>();
 
     private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
-            new SparseArray<AccessibilityConnectionWrapper>();
+            new SparseArray<>();
 
-    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>();
+    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();
 
-    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+    private final SparseArray<UserState> mUserStates = new SparseArray<>();
 
     private final UserManager mUserManager;
 
     private int mCurrentUserId = UserHandle.USER_OWNER;
 
-    private final LongArray mTempLongArray = new LongArray();
-
     //TODO: Remove this hack
     private boolean mInitialized;
 
@@ -439,10 +434,9 @@
             // to clients as being installed - it really is not.
             UserState userState = getUserStateLocked(resolvedUserId);
             if (userState.mUiAutomationService != null) {
-                List<AccessibilityServiceInfo> installedServices =
-                        new ArrayList<AccessibilityServiceInfo>();
+                List<AccessibilityServiceInfo> installedServices = new ArrayList<>();
                 installedServices.addAll(userState.mInstalledServices);
-                installedServices.remove(userState.mUiAutomationService);
+                installedServices.remove(userState.mUiAutomationService.mAccessibilityServiceInfo);
                 return installedServices;
             }
             return userState.mInstalledServices;
@@ -655,7 +649,6 @@
             // Automation service is not bound, so pretend it died to perform clean up.
             if (userState.mUiAutomationService != null
                     && serviceClient != null
-                    && userState.mUiAutomationService != null
                     && userState.mUiAutomationService.mServiceInterface != null
                     && userState.mUiAutomationService.mServiceInterface.asBinder()
                     == serviceClient.asBinder()) {
@@ -907,16 +900,6 @@
         }
     }
 
-    private void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) {
-        UserState state = getCurrentUserStateLocked();
-        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
-            Service service = state.mBoundServices.get(i);
-            if (mSecurityPolicy.canRetrieveWindowsLocked(service)) {
-                service.notifyWindowsChangedLocked(windows);
-            }
-        }
-    }
-
     /**
      * Removes an AccessibilityInteractionConnection.
      *
@@ -961,10 +944,8 @@
             try {
                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
                 mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
-            } catch (XmlPullParserException xppe) {
+            } catch (XmlPullParserException | IOException xppe) {
                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
-            } catch (IOException ioe) {
-                Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
             }
         }
 
@@ -1035,7 +1016,6 @@
             // An out of bounds exception can happen if services are going away
             // as the for loop is running. If that happens, just bail because
             // there are no more services to notify.
-            return;
         }
     }
 
@@ -1053,7 +1033,6 @@
      * Removes a service.
      *
      * @param service The service.
-     * @return True if the service was removed, false otherwise.
      */
     private void removeServiceLocked(Service service, UserState userState) {
         userState.mBoundServices.remove(service);
@@ -1093,7 +1072,8 @@
         }
 
         Set<String> packageNames = service.mPackageNames;
-        CharSequence packageName = event.getPackageName();
+        String packageName = (event.getPackageName() != null)
+                ? event.getPackageName().toString() : null;
 
         if (packageNames.isEmpty() || packageNames.contains(packageName)) {
             int feedbackType = service.mFeedbackType;
@@ -1386,8 +1366,7 @@
 
         if (mWindowsForAccessibilityCallback != null) {
             mWindowsForAccessibilityCallback = null;
-            mWindowManagerService.setWindowsForAccessibilityCallback(
-                    mWindowsForAccessibilityCallback);
+            mWindowManagerService.setWindowsForAccessibilityCallback(null);
         }
     }
 
@@ -1437,8 +1416,7 @@
     }
 
     private boolean readConfigurationForUserStateLocked(UserState userState) {
-        boolean somthingChanged = false;
-        somthingChanged |= readAccessibilityEnabledSettingLocked(userState);
+        boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState);
         somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
         somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
         somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
@@ -1868,7 +1846,7 @@
 
         int mFeedbackType;
 
-        Set<String> mPackageNames = new HashSet<String>();
+        Set<String> mPackageNames = new HashSet<>();
 
         boolean mIsDefault;
 
@@ -1890,20 +1868,16 @@
 
         boolean mIsAutomation;
 
-        final Rect mTempBounds1 = new Rect();
-
-        final Rect mTempBounds2 = new Rect();
-
         final ResolveInfo mResolveInfo;
 
         // the events pending events to be dispatched to this service
         final SparseArray<AccessibilityEvent> mPendingEvents =
-            new SparseArray<AccessibilityEvent>();
+            new SparseArray<>();
 
         final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher();
 
         final SparseArray<AccessibilityWindowInfo> mIntrospectedWindows =
-                new SparseArray<AccessibilityWindowInfo>();
+                new SparseArray<>();
 
         boolean mWasConnectedAndDied;
 
@@ -2106,7 +2080,7 @@
                 if (!permissionGranted) {
                     return null;
                 }
-                List<AccessibilityWindowInfo> windows = new ArrayList<AccessibilityWindowInfo>();
+                List<AccessibilityWindowInfo> windows = new ArrayList<>();
                 final int windowCount = mSecurityPolicy.mWindows.size();
                 for (int i = 0; i < windowCount; i++) {
                     AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i);
@@ -2646,51 +2620,6 @@
             }
         }
 
-        public void notifyWindowsChangedLocked(List<AccessibilityWindowInfo> windows) {
-            LongArray changedWindows = mTempLongArray;
-            changedWindows.clear();
-
-            // Figure out which windows the service cares about changed.
-            final int windowCount = windows.size();
-            for (int i = 0; i < windowCount; i++) {
-                AccessibilityWindowInfo newState = windows.get(i);
-                final int windowId = newState.getId();
-                AccessibilityWindowInfo oldState = mIntrospectedWindows.get(windowId);
-                if (oldState != null && oldState.changed(newState)) {
-                    oldState.recycle();
-                    mIntrospectedWindows.put(newState.getId(),
-                            AccessibilityWindowInfo.obtain(newState));
-                    changedWindows.add(windowId);
-                }
-            }
-
-            // Figure out which windows the service cares about went away.
-            final int introspectedWindowCount = mIntrospectedWindows.size();
-            for (int i = introspectedWindowCount - 1; i >= 0; i--) {
-                AccessibilityWindowInfo window = mIntrospectedWindows.valueAt(i);
-                if (changedWindows.indexOf(window.getId()) < 0 && !windows.contains(window)) {
-                    changedWindows.add(window.getId());
-                    mIntrospectedWindows.removeAt(i);
-                    window.recycle();
-                }
-            }
-
-            int[] windowIds = null;
-
-            final int changedWindowCount = changedWindows.size();
-            if (changedWindowCount > 0) {
-                windowIds = new int[changedWindowCount];
-                for (int i = 0; i < changedWindowCount; i++) {
-                    // Cast is fine as we use long array to cache ints.
-                    windowIds[i] = (int) changedWindows.get(i);
-                }
-                changedWindows.clear();
-            }
-
-            mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_WINDOWS_CHANGED,
-                    windowIds).sendToTarget();
-        }
-
         private void notifyGestureInternal(int gestureId) {
             final IAccessibilityServiceClient listener;
             synchronized (mLock) {
@@ -2725,20 +2654,6 @@
             }
         }
 
-        private void notifyWindowsChangedInternal(int[] windowIds) {
-            final IAccessibilityServiceClient listener;
-            synchronized (mLock) {
-                listener = mServiceInterface;
-            }
-            if (listener != null) {
-                try {
-                    listener.onWindowsChanged(windowIds);
-                } catch (RemoteException re) {
-                    Slog.e(LOG_TAG, "Error during sending windows to: " + mService, re);
-                }
-            }
-        }
-
         private void sendDownAndUpKeyEvents(int keyCode) {
             final long token = Binder.clearCallingIdentity();
 
@@ -2844,7 +2759,6 @@
             public static final int MSG_ON_KEY_EVENT = 2;
             public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 3;
             public static final int MSG_ON_KEY_EVENT_TIMEOUT = 4;
-            public static final int MSG_ON_WINDOWS_CHANGED = 5;
 
             public InvocationHandler(Looper looper) {
                 super(looper, null, true);
@@ -2874,11 +2788,6 @@
                         setOnKeyEventResult(false, eventState.sequence);
                     } break;
 
-                    case MSG_ON_WINDOWS_CHANGED: {
-                        final int[] windowIds = (int[]) message.obj;
-                        notifyWindowsChangedInternal(windowIds);
-                    } break;
-
                     default: {
                         throw new IllegalArgumentException("Unknown message: " + type);
                     }
@@ -3028,14 +2937,11 @@
         @Override
         public void onWindowsForAccessibilityChanged(List<WindowInfo> windows) {
             synchronized (mLock) {
-                List<WindowInfo> receivedWindows = (List<WindowInfo>) windows;
-
                 // Populate the windows to report.
-                List<AccessibilityWindowInfo> reportedWindows =
-                        new ArrayList<AccessibilityWindowInfo>();
-                final int receivedWindowCount = receivedWindows.size();
+                List<AccessibilityWindowInfo> reportedWindows = new ArrayList<>();
+                final int receivedWindowCount = windows.size();
                 for (int i = 0; i < receivedWindowCount; i++) {
-                    WindowInfo receivedWindow = receivedWindows.get(i);
+                    WindowInfo receivedWindow = windows.get(i);
                     AccessibilityWindowInfo reportedWindow = populateReportedWindow(
                             receivedWindow);
                     if (reportedWindow != null) {
@@ -3224,8 +3130,7 @@
             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
             | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
 
-        public final List<AccessibilityWindowInfo> mWindows =
-                new ArrayList<AccessibilityWindowInfo>();
+        public final List<AccessibilityWindowInfo> mWindows = new ArrayList<>();
 
         public int mActiveWindowId = INVALID_WINDOW_ID;
         public int mFocusedWindowId = INVALID_WINDOW_ID;
@@ -3265,7 +3170,9 @@
                 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
                 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
                 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
-                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
+                // Also windows changing should always be anounced.
+                case AccessibilityEvent.TYPE_WINDOWS_CHANGED: {
                     return true;
                 }
                 // All events for changes in window content should be
@@ -3327,7 +3234,7 @@
                 }
             }
 
-            notifyWindowsChangedLocked(mWindows);
+            notifyWindowsChanged();
 
             // If we are delaying a window state change event as the window
             // source was showing when it was fired, now is the time to send.
@@ -3452,10 +3359,18 @@
                     AccessibilityWindowInfo window = mWindows.get(i);
                     window.setActive(window.getId() == windowId);
                 }
-                notifyWindowsChangedLocked(mWindows);
+                notifyWindowsChanged();
             }
         }
 
+        private void notifyWindowsChanged() {
+            // Let the client know the windows changed.
+            AccessibilityEvent event = AccessibilityEvent.obtain(
+                    AccessibilityEvent.TYPE_WINDOWS_CHANGED);
+            event.setEventTime(SystemClock.uptimeMillis());
+            sendAccessibilityEvent(event, mCurrentUserId);
+        }
+
         public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
             return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId);
         }
@@ -3568,30 +3483,30 @@
         // Non-transient state.
 
         public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
-            new RemoteCallbackList<IAccessibilityManagerClient>();
+            new RemoteCallbackList<>();
 
         public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
-                new SparseArray<AccessibilityConnectionWrapper>();
+                new SparseArray<>();
 
-        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
+        public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();
 
         // Transient state.
 
         public final CopyOnWriteArrayList<Service> mBoundServices =
-                new CopyOnWriteArrayList<Service>();
+                new CopyOnWriteArrayList<>();
 
         public final Map<ComponentName, Service> mComponentNameToServiceMap =
-                new HashMap<ComponentName, Service>();
+                new HashMap<>();
 
         public final List<AccessibilityServiceInfo> mInstalledServices =
-                new ArrayList<AccessibilityServiceInfo>();
+                new ArrayList<>();
 
-        public final Set<ComponentName> mBindingServices = new HashSet<ComponentName>();
+        public final Set<ComponentName> mBindingServices = new HashSet<>();
 
-        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
+        public final Set<ComponentName> mEnabledServices = new HashSet<>();
 
         public final Set<ComponentName> mTouchExplorationGrantedServices =
-                new HashSet<ComponentName>();
+                new HashSet<>();
 
         public int mHandledFeedbackTypes = 0;
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 56b8c92..291d366 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -34,6 +34,7 @@
 import android.app.backup.IFullBackupRestoreObserver;
 import android.app.backup.IRestoreObserver;
 import android.app.backup.IRestoreSession;
+import android.app.job.JobParameters;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -78,6 +79,7 @@
 import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.Os;
+import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -119,6 +121,7 @@
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -154,6 +157,7 @@
     private static final String TAG = "BackupManagerService";
     private static final boolean DEBUG = true;
     private static final boolean MORE_DEBUG = false;
+    private static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
 
     // System-private key used for backing up an app's widget state.  Must
     // begin with U+FFxx by convention (we reserve all keys starting
@@ -239,7 +243,10 @@
     // order to give them time to enter the backup password.
     static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
 
-    private Context mContext;
+    // How long between attempts to perform a full-data backup of any given app
+    static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day
+
+    Context mContext;
     private PackageManager mPackageManager;
     IPackageManager mPackageManagerBinder;
     private IActivityManager mActivityManager;
@@ -313,17 +320,32 @@
     // Watch the device provisioning operation during setup
     ContentObserver mProvisionedObserver;
 
+    static BackupManagerService sInstance;
+    static BackupManagerService getInstance() {
+        // Always constructed during system bringup, so no need to lazy-init
+        return sInstance;
+    }
+
     public static final class Lifecycle extends SystemService {
-        private final BackupManagerService mService;
 
         public Lifecycle(Context context) {
             super(context);
-            mService = new BackupManagerService(context);
+            sInstance = new BackupManagerService(context);
         }
 
         @Override
         public void onStart() {
-            publishBinderService(Context.BACKUP_SERVICE, mService);
+            publishBinderService(Context.BACKUP_SERVICE, sInstance);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+                ContentResolver r = sInstance.mContext.getContentResolver();
+                boolean areEnabled = Settings.Secure.getInt(r,
+                        Settings.Secure.BACKUP_ENABLED, 0) != 0;
+                sInstance.setBackupEnabled(areEnabled);
+            }
         }
     }
 
@@ -542,6 +564,30 @@
     static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
     HashSet<String> mPendingInits = new HashSet<String>();  // transport names
 
+    // Round-robin queue for scheduling full backup passes
+    static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file
+    class FullBackupEntry implements Comparable<FullBackupEntry> {
+        String packageName;
+        long lastBackup;
+
+        FullBackupEntry(String pkg, long when) {
+            packageName = pkg;
+            lastBackup = when;
+        }
+
+        @Override
+        public int compareTo(FullBackupEntry other) {
+            if (lastBackup < other.lastBackup) return -1;
+            else if (lastBackup > other.lastBackup) return 1;
+            else return 0;
+        }
+    }
+
+    File mFullBackupScheduleFile;
+    // If we're running a schedule-driven full backup, this is the task instance doing it
+    PerformFullTransportBackupTask mRunningFullBackupTask; // inside mQueueLock
+    ArrayList<FullBackupEntry> mFullBackupQueue;           // inside mQueueLock
+
     // Utility: build a new random integer token
     int generateToken() {
         int token;
@@ -573,6 +619,17 @@
         return true;
     }
 
+    /* does *not* check overall backup eligibility policy! */
+    public static boolean appGetsFullBackup(PackageInfo pkg) {
+        if (pkg.applicationInfo.backupAgentName != null) {
+            // If it has an agent, it gets full backups only if it says so
+            return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
+        }
+
+        // No agent means we do full backups for it
+        return true;
+    }
+
     // ----- Asynchronous backup/restore handler thread -----
 
     private class BackupHandler extends Handler {
@@ -892,8 +949,6 @@
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
-        boolean areEnabled = Settings.Secure.getInt(resolver,
-                Settings.Secure.BACKUP_ENABLED, 0) != 0;
         mProvisioned = Settings.Global.getInt(resolver,
                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
         mAutoRestore = Settings.Secure.getInt(resolver,
@@ -987,6 +1042,7 @@
         mJournal = null;        // will be created on first use
 
         // Set up the various sorts of package tracking we do
+        mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
         initPackageTracking();
 
         // Build our mapping of uid to backup client services.  This implicitly
@@ -1050,9 +1106,6 @@
 
         // Power management
         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
-
-        // Start the backup passes going
-        setBackupEnabled(areEnabled);
     }
 
     private class RunBackupReceiver extends BroadcastReceiver {
@@ -1192,6 +1245,9 @@
             }
         }
 
+        // Resume the full-data backup queue
+        mFullBackupQueue = readFullBackupSchedule();
+
         // Register for broadcasts about package install, etc., so we can
         // update the provider list.
         IntentFilter filter = new IntentFilter();
@@ -1206,6 +1262,96 @@
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
     }
 
+    private ArrayList<FullBackupEntry> readFullBackupSchedule() {
+        ArrayList<FullBackupEntry> schedule = null;
+        synchronized (mQueueLock) {
+            if (mFullBackupScheduleFile.exists()) {
+                try {
+                    FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile);
+                    BufferedInputStream bufStream = new BufferedInputStream(fstream);
+                    DataInputStream in = new DataInputStream(bufStream);
+
+                    int version = in.readInt();
+                    if (version != SCHEDULE_FILE_VERSION) {
+                        Slog.e(TAG, "Unknown backup schedule version " + version);
+                        return null;
+                    }
+
+                    int N = in.readInt();
+                    schedule = new ArrayList<FullBackupEntry>(N);
+                    for (int i = 0; i < N; i++) {
+                        String pkgName = in.readUTF();
+                        long lastBackup = in.readLong();
+                        schedule.add(new FullBackupEntry(pkgName, lastBackup));
+                    }
+                    Collections.sort(schedule);
+                } catch (Exception e) {
+                    Slog.e(TAG, "Unable to read backup schedule", e);
+                    mFullBackupScheduleFile.delete();
+                    schedule = null;
+                }
+            }
+
+            if (schedule == null) {
+                // no prior queue record, or unable to read it.  Set up the queue
+                // from scratch.
+                List<PackageInfo> apps =
+                        PackageManagerBackupAgent.getStorableApplications(mPackageManager);
+                final int N = apps.size();
+                schedule = new ArrayList<FullBackupEntry>(N);
+                for (int i = 0; i < N; i++) {
+                    PackageInfo info = apps.get(i);
+                    if (appGetsFullBackup(info)) {
+                        schedule.add(new FullBackupEntry(info.packageName, 0));
+                    }
+                }
+                writeFullBackupScheduleAsync();
+            }
+        }
+        return schedule;
+    }
+
+    Runnable mFullBackupScheduleWriter = new Runnable() {
+        @Override public void run() {
+            synchronized (mQueueLock) {
+                try {
+                    ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
+                    DataOutputStream bufOut = new DataOutputStream(bufStream);
+                    bufOut.writeInt(SCHEDULE_FILE_VERSION);
+
+                    // version 1:
+                    //
+                    // [int] # of packages in the queue = N
+                    // N * {
+                    //     [utf8] package name
+                    //     [long] last backup time for this package
+                    //     }
+                    int N = mFullBackupQueue.size();
+                    bufOut.writeInt(N);
+
+                    for (int i = 0; i < N; i++) {
+                        FullBackupEntry entry = mFullBackupQueue.get(i);
+                        bufOut.writeUTF(entry.packageName);
+                        bufOut.writeLong(entry.lastBackup);
+                    }
+                    bufOut.flush();
+
+                    AtomicFile af = new AtomicFile(mFullBackupScheduleFile);
+                    FileOutputStream out = af.startWrite();
+                    out.write(bufStream.toByteArray());
+                    af.finishWrite(out);
+                } catch (Exception e) {
+                    Slog.e(TAG, "Unable to write backup schedule!", e);
+                }
+            }
+        }
+    };
+
+    private void writeFullBackupScheduleAsync() {
+        mBackupHandler.removeCallbacks(mFullBackupScheduleWriter);
+        mBackupHandler.post(mFullBackupScheduleWriter);
+    }
+
     private void parseLeftoverJournals() {
         for (File f : mJournalDir.listFiles()) {
             if (mJournal == null || f.compareTo(mJournal) != 0) {
@@ -1633,6 +1779,22 @@
                     }
                     addPackageParticipantsLocked(pkgList);
                 }
+                // If they're full-backup candidates, add them there instead
+                for (String packageName : pkgList) {
+                    try {
+                        PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
+                        long now = System.currentTimeMillis();
+                        if (appGetsFullBackup(app)) {
+                            enqueueFullBackup(packageName, now);
+                            scheduleNextFullBackupJob();
+                        }
+                    } catch (NameNotFoundException e) {
+                        // doesn't really exist; ignore it
+                        if (DEBUG) {
+                            Slog.i(TAG, "Can't resolve new app " + packageName);
+                        }
+                    }
+                }
             } else {
                 if (replacing) {
                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
@@ -3437,12 +3599,19 @@
     class PerformFullTransportBackupTask extends FullBackupTask {
         static final String TAG = "PFTBT";
         ArrayList<PackageInfo> mPackages;
+        boolean mUpdateSchedule;
         AtomicBoolean mLatch;
+        AtomicBoolean mKeepRunning;     // signal from job scheduler
+        FullBackupJob mJob;             // if a scheduled job needs to be finished afterwards
 
         PerformFullTransportBackupTask(IFullBackupRestoreObserver observer, 
-                String[] whichPackages, AtomicBoolean latch) {
+                String[] whichPackages, boolean updateSchedule,
+                FullBackupJob runningJob, AtomicBoolean latch) {
             super(observer);
+            mUpdateSchedule = updateSchedule;
             mLatch = latch;
+            mKeepRunning = new AtomicBoolean(true);
+            mJob = runningJob;
             mPackages = new ArrayList<PackageInfo>(whichPackages.length);
 
             for (String pkg : whichPackages) {
@@ -3474,119 +3643,164 @@
             }
         }
 
+        public void setRunning(boolean running) {
+            mKeepRunning.set(running);
+        }
+
         @Override
         public void run() {
-            IBackupTransport transport = getTransport(mCurrentTransport);
-            if (transport == null) {
-                Slog.w(TAG, "Transport not present; full data backup not performed");
-                return;
-            }
-
             // data from the app, passed to us for bridging to the transport
             ParcelFileDescriptor[] enginePipes = null;
 
             // Pipe through which we write data to the transport
             ParcelFileDescriptor[] transportPipes = null;
 
+            PackageInfo currentPackage;
+
             try {
+                IBackupTransport transport = getTransport(mCurrentTransport);
+                if (transport == null) {
+                    Slog.w(TAG, "Transport not present; full data backup not performed");
+                    return;
+                }
+
                 // Set up to send data to the transport
-                if (transport != null) {
-                    for (PackageInfo target : mPackages) {
-                        if (DEBUG) {
-                            Slog.i(TAG, "Initiating full-data transport backup of "
-                                    + target.packageName);
-                        }
-                        transportPipes = ParcelFileDescriptor.createPipe();
-
-                        // Tell the transport the data's coming
-                        int result = transport.performFullBackup(target, transportPipes[0]);
-                        if (result == BackupTransport.TRANSPORT_OK) {
-                            // The transport has its own copy of the read end of the pipe,
-                            // so close ours now
-                            transportPipes[0].close();
-                            transportPipes[0] = null;
-
-                            // Now set up the backup engine / data source end of things
-                            enginePipes = ParcelFileDescriptor.createPipe();
-                            AtomicBoolean runnerLatch = new AtomicBoolean(false);
-                            SinglePackageBackupRunner backupRunner =
-                                    new SinglePackageBackupRunner(enginePipes[1], target,
-                                            runnerLatch);
-                            // The runner dup'd the pipe half, so we close it here
-                            enginePipes[1].close();
-                            enginePipes[1] = null;
-
-                            // Spin off the runner to fetch the app's data and pipe it
-                            // into the engine pipes
-                            (new Thread(backupRunner, "package-backup-bridge")).start();
-
-                            // Read data off the engine pipe and pass it to the transport
-                            // pipe until we hit EOD on the input stream.
-                            FileInputStream in = new FileInputStream(
-                                    enginePipes[0].getFileDescriptor());
-                            FileOutputStream out = new FileOutputStream(
-                                    transportPipes[1].getFileDescriptor());
-                            byte[] buffer = new byte[8192];
-                            int nRead = 0;
-                            do {
-                                nRead = in.read(buffer);
-                                if (nRead > 0) {
-                                    out.write(buffer, 0, nRead);
-                                    result = transport.sendBackupData(nRead);
-                                }
-                            } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
-
-                            // In all cases we need to give the transport its finish callback
-                            int finishResult = transport.finishBackup();
-
-                            if (MORE_DEBUG) {
-                                Slog.i(TAG, "Done trying to send backup data: result="
-                                        + result + " finishResult=" + finishResult);
-                            }
-
-                            // If we were otherwise in a good state, now interpret the final
-                            // result based on what finishBackup() returned.  If we're in a
-                            // failure case already, preserve that result and ignore whatever
-                            // finishBackup() reported.
-                            if (result == BackupTransport.TRANSPORT_OK) {
-                                result = finishResult;
-                            }
-
-                            if (result != BackupTransport.TRANSPORT_OK) {
-                                Slog.e(TAG, "Error " + result
-                                        + " backing up " + target.packageName);
-                            }
-                        }
-
-                        if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
-                            if (DEBUG) {
-                                Slog.i(TAG, "Transport rejected backup of " + target.packageName
-                                        + ", skipping");
-                            }
-                            // do nothing, clean up, and continue looping
-                        } else if (result != BackupTransport.TRANSPORT_OK) {
-                            if (DEBUG) {
-                                Slog.i(TAG, "Transport failed; aborting backup: " + result);
-                                return;
-                            }
-                        }
-                        cleanUpPipes(transportPipes);
-                        cleanUpPipes(enginePipes);
-                    }
-
+                final int N = mPackages.size();
+                for (int i = 0; i < N; i++) {
+                    currentPackage = mPackages.get(i);
                     if (DEBUG) {
-                        Slog.i(TAG, "Full backup completed.");
+                        Slog.i(TAG, "Initiating full-data transport backup of "
+                                + currentPackage.packageName);
                     }
+                    transportPipes = ParcelFileDescriptor.createPipe();
+
+                    // Tell the transport the data's coming
+                    int result = transport.performFullBackup(currentPackage,
+                            transportPipes[0]);
+                    if (result == BackupTransport.TRANSPORT_OK) {
+                        // The transport has its own copy of the read end of the pipe,
+                        // so close ours now
+                        transportPipes[0].close();
+                        transportPipes[0] = null;
+
+                        // Now set up the backup engine / data source end of things
+                        enginePipes = ParcelFileDescriptor.createPipe();
+                        AtomicBoolean runnerLatch = new AtomicBoolean(false);
+                        SinglePackageBackupRunner backupRunner =
+                                new SinglePackageBackupRunner(enginePipes[1], currentPackage,
+                                        runnerLatch);
+                        // The runner dup'd the pipe half, so we close it here
+                        enginePipes[1].close();
+                        enginePipes[1] = null;
+
+                        // Spin off the runner to fetch the app's data and pipe it
+                        // into the engine pipes
+                        (new Thread(backupRunner, "package-backup-bridge")).start();
+
+                        // Read data off the engine pipe and pass it to the transport
+                        // pipe until we hit EOD on the input stream.
+                        FileInputStream in = new FileInputStream(
+                                enginePipes[0].getFileDescriptor());
+                        FileOutputStream out = new FileOutputStream(
+                                transportPipes[1].getFileDescriptor());
+                        byte[] buffer = new byte[8192];
+                        int nRead = 0;
+                        do {
+                            if (!mKeepRunning.get()) {
+                                if (DEBUG_SCHEDULING) {
+                                    Slog.i(TAG, "Full backup task told to stop");
+                                }
+                                break;
+                            }
+                            nRead = in.read(buffer);
+                            if (nRead > 0) {
+                                out.write(buffer, 0, nRead);
+                                result = transport.sendBackupData(nRead);
+                            }
+                        } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
+
+                        int finishResult;
+
+                        if (!mKeepRunning.get()) {
+                            result = BackupTransport.TRANSPORT_ERROR;
+                            // TODO: tell the transport to abort the backup
+                            Slog.w(TAG, "TODO: tell transport to halt & roll back");
+                        }
+
+                        // In all cases we need to give the transport its finish callback
+                        finishResult = transport.finishBackup();
+
+                        if (MORE_DEBUG) {
+                            Slog.i(TAG, "Done trying to send backup data: result="
+                                    + result + " finishResult=" + finishResult);
+                        }
+
+                        // If we were otherwise in a good state, now interpret the final
+                        // result based on what finishBackup() returned.  If we're in a
+                        // failure case already, preserve that result and ignore whatever
+                        // finishBackup() reported.
+                        if (result == BackupTransport.TRANSPORT_OK) {
+                            result = finishResult;
+                        }
+
+                        if (result != BackupTransport.TRANSPORT_OK) {
+                            Slog.e(TAG, "Error " + result
+                                    + " backing up " + currentPackage.packageName);
+                        }
+                    }
+
+                    // Roll this package to the end of the backup queue if we're
+                    // in a queue-driven mode (regardless of success/failure)
+                    if (mUpdateSchedule) {
+                        enqueueFullBackup(currentPackage.packageName,
+                                System.currentTimeMillis());
+                    }
+
+                    if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "Transport rejected backup of "
+                                    + currentPackage.packageName
+                                    + ", skipping");
+                        }
+                        // do nothing, clean up, and continue looping
+                    } else if (result != BackupTransport.TRANSPORT_OK) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "Transport failed; aborting backup: " + result);
+                            return;
+                        }
+                    }
+                    cleanUpPipes(transportPipes);
+                    cleanUpPipes(enginePipes);
+                    currentPackage = null;
+                }
+
+                if (DEBUG) {
+                    Slog.i(TAG, "Full backup completed.");
                 }
             } catch (Exception e) {
                 Slog.w(TAG, "Exception trying full transport backup", e);
             } finally {
                 cleanUpPipes(transportPipes);
                 cleanUpPipes(enginePipes);
+
+                if (mJob != null) {
+                    mJob.finishBackupPass();
+                }
+
+                synchronized (mQueueLock) {
+                    mRunningFullBackupTask = null;
+                }
+
                 synchronized (mLatch) {
                     mLatch.set(true);
                     mLatch.notifyAll();
                 }
+
+                // Now that we're actually done with schedule-driven work, reschedule
+                // the next pass based on the new queue state.
+                if (mUpdateSchedule) {
+                    scheduleNextFullBackupJob();
+                }
             }
         }
 
@@ -3653,6 +3867,146 @@
         }
     }
 
+    // ----- Full-data backup scheduling -----
+
+    /**
+     * Schedule a job to tell us when it's a good time to run a full backup
+     */
+    void scheduleNextFullBackupJob() {
+        synchronized (mQueueLock) {
+            if (mFullBackupQueue.size() > 0) {
+                // schedule the next job at the point in the future when the least-recently
+                // backed up app comes due for backup again; or immediately if it's already
+                // due.
+                long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup;
+                long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup;
+                final long latency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL)
+                        ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0;
+                Runnable r = new Runnable() {
+                    @Override public void run() {
+                        FullBackupJob.schedule(mContext, latency);
+                    }
+                };
+                mBackupHandler.postDelayed(r, 2500);
+            } else {
+                if (DEBUG_SCHEDULING) {
+                    Slog.i(TAG, "Full backup queue empty; not scheduling");
+                }
+            }
+        }
+    }
+
+    /**
+     * Enqueue full backup for the given app, with a note about when it last ran.
+     */
+    void enqueueFullBackup(String packageName, long lastBackedUp) {
+        FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
+        synchronized (mQueueLock) {
+            int N = mFullBackupQueue.size();
+            // First, sanity check that we aren't adding a duplicate.  Slow but
+            // straightforward; we'll have at most on the order of a few hundred
+            // items in this list.
+            for (int i = N-1; i >= 0; i--) {
+                final FullBackupEntry e = mFullBackupQueue.get(i);
+                if (packageName.equals(e.packageName)) {
+                    if (DEBUG) {
+                        Slog.w(TAG, "Removing schedule queue dupe of " + packageName);
+                    }
+                    mFullBackupQueue.remove(i);
+                }
+            }
+
+            // This is also slow but easy for modest numbers of apps: work backwards
+            // from the end of the queue until we find an item whose last backup
+            // time was before this one, then insert this new entry after it.
+            int which;
+            for (which = mFullBackupQueue.size() - 1; which >= 0; which--) {
+                final FullBackupEntry entry = mFullBackupQueue.get(which);
+                if (entry.lastBackup <= lastBackedUp) {
+                    mFullBackupQueue.add(which + 1, newEntry);
+                    break;
+                }
+            }
+            if (which < 0) {
+                // this one is earlier than any existing one, so prepend
+                mFullBackupQueue.add(0, newEntry);
+            }
+        }
+        writeFullBackupScheduleAsync();
+    }
+
+    /**
+     * Conditions are right for a full backup operation, so run one.  The model we use is
+     * to perform one app backup per scheduled job execution, and to reschedule the job
+     * with zero latency as long as conditions remain right and we still have work to do.
+     *
+     * @return Whether ongoing work will continue.  The return value here will be passed
+     *         along as the return value to the scheduled job's onStartJob() callback.
+     */
+    boolean beginFullBackup(FullBackupJob scheduledJob) {
+        long now = System.currentTimeMillis();
+        FullBackupEntry entry = null;
+
+        if (DEBUG_SCHEDULING) {
+            Slog.i(TAG, "Beginning scheduled full backup operation");
+        }
+
+        // Great; we're able to run full backup jobs now.  See if we have any work to do.
+        synchronized (mQueueLock) {
+            if (mRunningFullBackupTask != null) {
+                Slog.e(TAG, "Backup triggered but one already/still running!");
+                return false;
+            }
+
+            if (mFullBackupQueue.size() == 0) {
+                // no work to do so just bow out
+                if (DEBUG) {
+                    Slog.i(TAG, "Backup queue empty; doing nothing");
+                }
+                return false;
+            }
+
+            entry = mFullBackupQueue.get(0);
+            long timeSinceRun = now - entry.lastBackup;
+            if (timeSinceRun < MIN_FULL_BACKUP_INTERVAL) {
+                // It's too early to back up the next thing in the queue, so bow out
+                if (MORE_DEBUG) {
+                    Slog.i(TAG, "Device ready but too early to back up next app");
+                }
+                final long latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
+                mBackupHandler.post(new Runnable() {
+                    @Override public void run() {
+                        FullBackupJob.schedule(mContext, latency);
+                    }
+                });
+                return false;
+            }
+
+            // Okay, the top thing is runnable now.  Pop it off and get going.
+            mFullBackupQueue.remove(0);
+            AtomicBoolean latch = new AtomicBoolean(false);
+            String[] pkg = new String[] {entry.packageName};
+            mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true,
+                    scheduledJob, latch);
+            (new Thread(mRunningFullBackupTask)).start();
+        }
+
+        return true;
+    }
+
+    // The job scheduler says our constraints don't hold any more,
+    // so tear down any ongoing backup task right away.
+    void endFullBackup() {
+        synchronized (mQueueLock) {
+            if (mRunningFullBackupTask != null) {
+                if (DEBUG_SCHEDULING) {
+                    Slog.i(TAG, "Telling running backup to stop");
+                }
+                mRunningFullBackupTask.setRunning(false);
+            }
+        }
+    }
+
     // ----- Restore infrastructure -----
 
     abstract class RestoreEngine {
@@ -6645,8 +6999,8 @@
             UnifiedRestoreState nextState = UnifiedRestoreState.FINAL;
             try {
                 mRestoreDescription = mTransport.nextRestorePackage();
-                final int type = mRestoreDescription.getDataType();
-                final String pkgName = mRestoreDescription.getPackageName();
+                final String pkgName = (mRestoreDescription != null)
+                        ? mRestoreDescription.getPackageName() : null;
                 if (pkgName == null) {
                     Slog.e(TAG, "Failure getting next package name");
                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
@@ -6717,6 +7071,7 @@
 
                 // Reset per-package preconditions and fire the appropriate next state
                 mWidgetData = null;
+                final int type = mRestoreDescription.getDataType();
                 if (type == RestoreDescription.TYPE_KEY_VALUE) {
                     nextState = UnifiedRestoreState.RESTORE_KEYVALUE;
                 } else if (type == RestoreDescription.TYPE_FULL_STREAM) {
@@ -7725,7 +8080,8 @@
         }
 
         AtomicBoolean latch = new AtomicBoolean(false);
-        PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, pkgNames, latch);
+        PerformFullTransportBackupTask task =
+                new PerformFullTransportBackupTask(null, pkgNames, false, null, latch);
         (new Thread(task, "full-transport-master")).start();
         synchronized (latch) {
             try {
@@ -7914,6 +8270,7 @@
                 if (enable && !wasEnabled && mProvisioned) {
                     // if we've just been enabled, start scheduling backup passes
                     startBackupAlarmsLocked(BACKUP_INTERVAL);
+                    scheduleNextFullBackupJob();
                 } else if (!enable) {
                     // No longer enabled, so stop running backups
                     if (DEBUG) Slog.i(TAG, "Opting out of backup");
@@ -8470,12 +8827,6 @@
                 throw new SecurityException("No permission to restore other packages");
             }
 
-            // If the package has no backup agent, we obviously cannot proceed
-            if (app.applicationInfo.backupAgentName == null) {
-                Slog.w(TAG, "Asked to restore package " + packageName + " with no agent");
-                return -1;
-            }
-
             // So far so good; we're allowed to try to restore this package.  Now
             // check whether there is data for it in the current dataset, falling back
             // to the ancestral dataset if not.
@@ -8658,10 +9009,16 @@
                 pw.println("    " + pkg);
             }
 
-            pw.println("Pending backup: " + mPendingBackups.size());
+            pw.println("Pending key/value backup: " + mPendingBackups.size());
             for (BackupRequest req : mPendingBackups.values()) {
                 pw.println("    " + req);
             }
+
+            pw.println("Full backup queue:" + mFullBackupQueue.size());
+            for (FullBackupEntry entry : mFullBackupQueue) {
+                pw.print("    "); pw.print(entry.lastBackup);
+                pw.print(" : "); pw.println(entry.packageName);
+            }
         }
     }
 }
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
new file mode 100644
index 0000000..deb2293
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -0,0 +1,78 @@
+/*
+ * 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.backup;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.app.job.JobInfo.NetworkType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.Slog;
+
+public class FullBackupJob extends JobService {
+    private static final String TAG = "FullBackupJob";
+    private static final boolean DEBUG = true;
+
+    private static ComponentName sIdleService =
+            new ComponentName("android", FullBackupJob.class.getName());
+
+    private static final int JOB_ID = 0x5038;
+
+    JobParameters mParams;
+
+    public static void schedule(Context ctx, long minDelay) {
+        JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService)
+                .setRequiresDeviceIdle(true)
+                .setRequiredNetworkCapabilities(NetworkType.UNMETERED)
+                .setRequiresCharging(true);
+        if (minDelay > 0) {
+            builder.setMinimumLatency(minDelay);
+        }
+        js.schedule(builder.build());
+    }
+
+    // callback from the Backup Manager Service: it's finished its work for this pass
+    public void finishBackupPass() {
+        if (mParams != null) {
+            jobFinished(mParams, false);
+            mParams = null;
+        }
+    }
+
+    // ----- scheduled job interface -----
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        mParams = params;
+        BackupManagerService service = BackupManagerService.getInstance();
+        return service.beginFullBackup(this);
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        if (mParams != null) {
+            mParams = null;
+            BackupManagerService service = BackupManagerService.getInstance();
+            service.endFullBackup();
+        }
+        return false;
+    }
+
+}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 5a510a9..13e1b37 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -96,8 +96,6 @@
     final SparseArray<HashMap<String, Ops>> mUidOps
             = new SparseArray<HashMap<String, Ops>>();
 
-    private int mDeviceOwnerUid;
-    private final SparseIntArray mProfileOwnerUids = new SparseIntArray();
     private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
 
     public final static class Ops extends SparseArray<Op> {
@@ -873,15 +871,7 @@
                     }
                 }
             }
-            if (userHandle == UserHandle.USER_OWNER) {
-                if (uid != mDeviceOwnerUid) {
-                    return true;
-                }
-            } else {
-                if (uid != mProfileOwnerUids.get(userHandle, -1)) {
-                    return true;
-                }
-            }
+            return true;
         }
         return false;
     }
@@ -1256,35 +1246,6 @@
     }
 
     @Override
-    public void setDeviceOwner(String packageName) throws RemoteException {
-        checkSystemUid("setDeviceOwner");
-        try {
-            mDeviceOwnerUid = mContext.getPackageManager().getPackageUid(packageName,
-                    UserHandle.USER_OWNER);
-        } catch (NameNotFoundException e) {
-            Log.e(TAG, "Could not find Device Owner UID");
-            mDeviceOwnerUid = -1;
-            throw new IllegalArgumentException("Could not find device owner package "
-                    + packageName);
-        }
-    }
-
-    @Override
-    public void setProfileOwner(String packageName, int userHandle) throws RemoteException {
-        checkSystemUid("setProfileOwner");
-        try {
-            int uid = mContext.getPackageManager().getPackageUid(packageName,
-                    userHandle);
-            mProfileOwnerUids.put(userHandle, uid);
-        } catch (NameNotFoundException e) {
-            Log.e(TAG, "Could not find Profile Owner UID");
-            mProfileOwnerUids.put(userHandle, -1);
-            throw new IllegalArgumentException("Could not find profile owner package "
-                    + packageName);
-        }
-    }
-
-    @Override
     public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
         checkSystemUid("setUserRestrictions");
         boolean[] opRestrictions = mOpRestrictions.get(userHandle);
@@ -1306,10 +1267,6 @@
     public void removeUser(int userHandle) throws RemoteException {
         checkSystemUid("removeUser");
         mOpRestrictions.remove(userHandle);
-        final int index = mProfileOwnerUids.indexOfKey(userHandle);
-        if (index >= 0) {
-            mProfileOwnerUids.removeAt(index);
-        }
     }
 
     private void checkSystemUid(String function) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index abee0c6..7349ebf 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -74,6 +74,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkFactory;
+import android.net.NetworkMisc;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
@@ -182,8 +183,8 @@
 public class ConnectivityService extends IConnectivityManager.Stub {
     private static final String TAG = "ConnectivityService";
 
-    private static final boolean DBG = false;
-    private static final boolean VDBG = false; // STOPSHIP
+    private static final boolean DBG = true;
+    private static final boolean VDBG = true; // STOPSHIP
 
     // network sampling debugging
     private static final boolean SAMPLE_DBG = false;
@@ -286,12 +287,6 @@
     private static final int DISABLED = 0;
 
     /**
-     * used internally as a delayed event to make us switch back to the
-     * default network
-     */
-    private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1;
-
-    /**
      * used internally to change our mobile data enabled flag
      */
     private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
@@ -415,10 +410,6 @@
     /** Handler used for incoming {@link NetworkStateTracker} events. */
     final private NetworkStateTrackerHandler mTrackerHandler;
 
-    // list of DeathRecipients used to make sure features are turned off when
-    // a process dies
-    private List<FeatureUser> mFeatureUsers;
-
     private boolean mSystemReady;
     private Intent mInitialBroadcast;
 
@@ -764,8 +755,6 @@
             mNetRequestersPids[i] = new ArrayList<Integer>();
         }
 
-        mFeatureUsers = new ArrayList<FeatureUser>();
-
         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
                 && SystemProperties.get("ro.build.type").equals("eng");
 
@@ -788,7 +777,7 @@
             }
         }
 
-        mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
+        mTethering = new Tethering(mContext, mNetd, statsService, mHandler.getLooper());
 
         //set up the listener for user state for creating user VPNs
         IntentFilter intentFilter = new IntentFilter();
@@ -816,13 +805,7 @@
         mDataConnectionStats = new DataConnectionStats(mContext);
         mDataConnectionStats.startMonitoring();
 
-        // start network sampling ..
-        Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null);
-        mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext,
-                SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0);
-
         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
@@ -1321,354 +1304,6 @@
     };
 
     /**
-     * Used to notice when the calling process dies so we can self-expire
-     *
-     * Also used to know if the process has cleaned up after itself when
-     * our auto-expire timer goes off.  The timer has a link to an object.
-     *
-     */
-    private class FeatureUser implements IBinder.DeathRecipient {
-        int mNetworkType;
-        String mFeature;
-        IBinder mBinder;
-        int mPid;
-        int mUid;
-        long mCreateTime;
-
-        FeatureUser(int type, String feature, IBinder binder) {
-            super();
-            mNetworkType = type;
-            mFeature = feature;
-            mBinder = binder;
-            mPid = getCallingPid();
-            mUid = getCallingUid();
-            mCreateTime = System.currentTimeMillis();
-
-            try {
-                mBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                binderDied();
-            }
-        }
-
-        void unlinkDeathRecipient() {
-            mBinder.unlinkToDeath(this, 0);
-        }
-
-        public void binderDied() {
-            log("ConnectivityService FeatureUser binderDied(" +
-                    mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
-                    (System.currentTimeMillis() - mCreateTime) + " mSec ago");
-            stopUsingNetworkFeature(this, false);
-        }
-
-        public void expire() {
-            if (VDBG) {
-                log("ConnectivityService FeatureUser expire(" +
-                        mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
-                        (System.currentTimeMillis() - mCreateTime) + " mSec ago");
-            }
-            stopUsingNetworkFeature(this, false);
-        }
-
-        public boolean isSameUser(FeatureUser u) {
-            if (u == null) return false;
-
-            return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature);
-        }
-
-        public boolean isSameUser(int pid, int uid, int networkType, String feature) {
-            if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) &&
-                TextUtils.equals(mFeature, feature)) {
-                return true;
-            }
-            return false;
-        }
-
-        public String toString() {
-            return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
-                    (System.currentTimeMillis() - mCreateTime) + " mSec ago";
-        }
-    }
-
-    // javadoc from interface
-    public int startUsingNetworkFeature(int networkType, String feature,
-            IBinder binder) {
-        long startTime = 0;
-        if (DBG) {
-            startTime = SystemClock.elapsedRealtime();
-        }
-        if (VDBG) {
-            log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid="
-                    + Binder.getCallingUid());
-        }
-        enforceChangePermission();
-        try {
-            if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
-                    mNetConfigs[networkType] == null) {
-                return PhoneConstants.APN_REQUEST_FAILED;
-            }
-
-            FeatureUser f = new FeatureUser(networkType, feature, binder);
-
-            // TODO - move this into individual networktrackers
-            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
-
-            if (mLockdownEnabled) {
-                // Since carrier APNs usually aren't available from VPN
-                // endpoint, mark them as unavailable.
-                return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
-            }
-
-            if (mProtectedNetworks.contains(usedNetworkType)) {
-                enforceConnectivityInternalPermission();
-            }
-
-            // if UID is restricted, don't allow them to bring up metered APNs
-            final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
-            final int uidRules;
-            synchronized (mRulesLock) {
-                uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
-            }
-            if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
-                return PhoneConstants.APN_REQUEST_FAILED;
-            }
-
-            NetworkStateTracker network = mNetTrackers[usedNetworkType];
-            if (network != null) {
-                Integer currentPid = new Integer(getCallingPid());
-                if (usedNetworkType != networkType) {
-                    NetworkInfo ni = network.getNetworkInfo();
-
-                    if (ni.isAvailable() == false) {
-                        if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
-                            if (DBG) log("special network not available ni=" + ni.getTypeName());
-                            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
-                        } else {
-                            // else make the attempt anyway - probably giving REQUEST_STARTED below
-                            if (DBG) {
-                                log("special network not available, but try anyway ni=" +
-                                        ni.getTypeName());
-                            }
-                        }
-                    }
-
-                    int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
-
-                    synchronized(this) {
-                        boolean addToList = true;
-                        if (restoreTimer < 0) {
-                            // In case there is no timer is specified for the feature,
-                            // make sure we don't add duplicate entry with the same request.
-                            for (FeatureUser u : mFeatureUsers) {
-                                if (u.isSameUser(f)) {
-                                    // Duplicate user is found. Do not add.
-                                    addToList = false;
-                                    break;
-                                }
-                            }
-                        }
-
-                        if (addToList) mFeatureUsers.add(f);
-                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
-                            // this gets used for per-pid dns when connected
-                            mNetRequestersPids[usedNetworkType].add(currentPid);
-                        }
-                    }
-
-                    if (restoreTimer >= 0) {
-                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
-                                EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
-                    }
-
-                    if ((ni.isConnectedOrConnecting() == true) &&
-                            !network.isTeardownRequested()) {
-                        if (ni.isConnected() == true) {
-                            final long token = Binder.clearCallingIdentity();
-                            try {
-                                // add the pid-specific dns
-                                handleDnsConfigurationChange(usedNetworkType);
-                                if (VDBG) log("special network already active");
-                            } finally {
-                                Binder.restoreCallingIdentity(token);
-                            }
-                            return PhoneConstants.APN_ALREADY_ACTIVE;
-                        }
-                        if (VDBG) log("special network already connecting");
-                        return PhoneConstants.APN_REQUEST_STARTED;
-                    }
-
-                    // check if the radio in play can make another contact
-                    // assume if cannot for now
-
-                    if (DBG) {
-                        log("startUsingNetworkFeature reconnecting to " + networkType + ": " +
-                                feature);
-                    }
-                    if (network.reconnect()) {
-                        if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED");
-                        return PhoneConstants.APN_REQUEST_STARTED;
-                    } else {
-                        if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED");
-                        return PhoneConstants.APN_REQUEST_FAILED;
-                    }
-                } else {
-                    // need to remember this unsupported request so we respond appropriately on stop
-                    synchronized(this) {
-                        mFeatureUsers.add(f);
-                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
-                            // this gets used for per-pid dns when connected
-                            mNetRequestersPids[usedNetworkType].add(currentPid);
-                        }
-                    }
-                    if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature.");
-                    return -1;
-                }
-            }
-            if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE");
-            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
-         } finally {
-            if (DBG) {
-                final long execTime = SystemClock.elapsedRealtime() - startTime;
-                if (execTime > 250) {
-                    loge("startUsingNetworkFeature took too long: " + execTime + "ms");
-                } else {
-                    if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms");
-                }
-            }
-         }
-    }
-
-    // javadoc from interface
-    public int stopUsingNetworkFeature(int networkType, String feature) {
-        enforceChangePermission();
-
-        int pid = getCallingPid();
-        int uid = getCallingUid();
-
-        FeatureUser u = null;
-        boolean found = false;
-
-        synchronized(this) {
-            for (FeatureUser x : mFeatureUsers) {
-                if (x.isSameUser(pid, uid, networkType, feature)) {
-                    u = x;
-                    found = true;
-                    break;
-                }
-            }
-        }
-        if (found && u != null) {
-            if (VDBG) log("stopUsingNetworkFeature: X");
-            // stop regardless of how many other time this proc had called start
-            return stopUsingNetworkFeature(u, true);
-        } else {
-            // none found!
-            if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring");
-            return 1;
-        }
-    }
-
-    private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
-        int networkType = u.mNetworkType;
-        String feature = u.mFeature;
-        int pid = u.mPid;
-        int uid = u.mUid;
-
-        NetworkStateTracker tracker = null;
-        boolean callTeardown = false;  // used to carry our decision outside of sync block
-
-        if (VDBG) {
-            log("stopUsingNetworkFeature: net " + networkType + ": " + feature);
-        }
-
-        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
-            if (DBG) {
-                log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
-                        ", net is invalid");
-            }
-            return -1;
-        }
-
-        // need to link the mFeatureUsers list with the mNetRequestersPids state in this
-        // sync block
-        synchronized(this) {
-            // check if this process still has an outstanding start request
-            if (!mFeatureUsers.contains(u)) {
-                if (VDBG) {
-                    log("stopUsingNetworkFeature: this process has no outstanding requests" +
-                        ", ignoring");
-                }
-                return 1;
-            }
-            u.unlinkDeathRecipient();
-            mFeatureUsers.remove(mFeatureUsers.indexOf(u));
-            // If we care about duplicate requests, check for that here.
-            //
-            // This is done to support the extension of a request - the app
-            // can request we start the network feature again and renew the
-            // auto-shutoff delay.  Normal "stop" calls from the app though
-            // do not pay attention to duplicate requests - in effect the
-            // API does not refcount and a single stop will counter multiple starts.
-            if (ignoreDups == false) {
-                for (FeatureUser x : mFeatureUsers) {
-                    if (x.isSameUser(u)) {
-                        if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring");
-                        return 1;
-                    }
-                }
-            }
-
-            // TODO - move to individual network trackers
-            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
-
-            tracker =  mNetTrackers[usedNetworkType];
-            if (tracker == null) {
-                if (DBG) {
-                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
-                            " no known tracker for used net type " + usedNetworkType);
-                }
-                return -1;
-            }
-            if (usedNetworkType != networkType) {
-                Integer currentPid = new Integer(pid);
-                mNetRequestersPids[usedNetworkType].remove(currentPid);
-
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    reassessPidDns(pid, true);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-                flushVmDnsCache();
-                if (mNetRequestersPids[usedNetworkType].size() != 0) {
-                    if (VDBG) {
-                        log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
-                                " others still using it");
-                    }
-                    return 1;
-                }
-                callTeardown = true;
-            } else {
-                if (DBG) {
-                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
-                            " not a known feature - dropping");
-                }
-            }
-        }
-
-        if (callTeardown) {
-            if (DBG) {
-                log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature);
-            }
-            tracker.teardown();
-            return 1;
-        } else {
-            return -1;
-        }
-    }
-
-    /**
      * Ensure that a network route exists to deliver traffic to the specified
      * host via the specified network interface.
      * @param networkType the type of the network over which traffic to the
@@ -2144,6 +1779,14 @@
     }
 
     void systemReady() {
+        // start network sampling ..
+        Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
+        intent.setPackage(mContext.getPackageName());
+
+        mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext,
+                SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0);
+        setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
+
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
             mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
         }
@@ -2937,7 +2580,9 @@
                     }
                     try {
                         mNetd.addVpnUidRanges(nai.network.netId, (UidRange[])msg.obj);
-                    } catch (RemoteException e) {
+                    } catch (Exception e) {
+                        // Never crash!
+                        loge("Exception in addVpnUidRanges: " + e);
                     }
                     break;
                 }
@@ -2949,7 +2594,39 @@
                     }
                     try {
                         mNetd.removeVpnUidRanges(nai.network.netId, (UidRange[])msg.obj);
-                    } catch (RemoteException e) {
+                    } catch (Exception e) {
+                        // Never crash!
+                        loge("Exception in removeVpnUidRanges: " + e);
+                    }
+                    break;
+                }
+                case NetworkAgent.EVENT_BLOCK_ADDRESS_FAMILY: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai == null) {
+                        loge("EVENT_BLOCK_ADDRESS_FAMILY from unknown NetworkAgent");
+                        break;
+                    }
+                    try {
+                        mNetd.blockAddressFamily((Integer) msg.obj, nai.network.netId,
+                                nai.linkProperties.getInterfaceName());
+                    } catch (Exception e) {
+                        // Never crash!
+                        loge("Exception in blockAddressFamily: " + e);
+                    }
+                    break;
+                }
+                case NetworkAgent.EVENT_UNBLOCK_ADDRESS_FAMILY: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai == null) {
+                        loge("EVENT_UNBLOCK_ADDRESS_FAMILY from unknown NetworkAgent");
+                        break;
+                    }
+                    try {
+                        mNetd.unblockAddressFamily((Integer) msg.obj, nai.network.netId,
+                                nai.linkProperties.getInterfaceName());
+                    } catch (Exception e) {
+                        // Never crash!
+                        loge("Exception in blockAddressFamily: " + e);
                     }
                     break;
                 }
@@ -3221,6 +2898,7 @@
                 return;
             }
             if (DBG) log("releasing NetworkRequest " + request);
+            nri.unlinkDeathRecipient();
             mNetworkRequests.remove(request);
             // tell the network currently servicing this that it's no longer interested
             NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
@@ -3289,11 +2967,6 @@
                     }
                     break;
                 }
-                case EVENT_RESTORE_DEFAULT_NETWORK: {
-                    FeatureUser u = (FeatureUser)msg.obj;
-                    u.expire();
-                    break;
-                }
                 case EVENT_INET_CONDITION_CHANGE: {
                     int netType = msg.arg1;
                     int condition = msg.arg2;
@@ -4355,6 +4028,7 @@
 
                 // First wait until we can start using hipri
                 Binder binder = new Binder();
+/*
                 while(SystemClock.elapsedRealtime() < endTime) {
                     int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                             Phone.FEATURE_ENABLE_HIPRI, binder);
@@ -4367,7 +4041,7 @@
                     result = CMP_RESULT_CODE_NO_CONNECTION;
                     sleep(POLLING_SLEEP_SEC);
                 }
-
+*/
                 // Continue trying to connect until time has run out
                 while(SystemClock.elapsedRealtime() < endTime) {
                     try {
@@ -4550,8 +4224,8 @@
             } finally {
                 log("isMobileOk: F stop hipri");
                 mCs.setEnableFailFastMobileData(DctConstants.DISABLED);
-                mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                        Phone.FEATURE_ENABLE_HIPRI);
+//                mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+//                        Phone.FEATURE_ENABLE_HIPRI);
 
                 // Wait for hipri to disconnect.
                 long endTime = SystemClock.elapsedRealtime() + 5000;
@@ -5107,6 +4781,10 @@
         }
     }
 
+    /**
+     * Tracks info about the requester.
+     * Also used to notice when the calling process dies so we can self-expire
+     */
     private class NetworkRequestInfo implements IBinder.DeathRecipient {
         static final boolean REQUEST = true;
         static final boolean LISTEN = false;
@@ -5160,11 +4838,27 @@
             enforceChangePermission();
         }
 
+        networkCapabilities = new NetworkCapabilities(networkCapabilities);
+
+        // if UID is restricted, don't allow them to bring up metered APNs
+        if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+                == false) {
+            final int uidRules;
+            synchronized(mRulesLock) {
+                uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
+            }
+            if ((uidRules & RULE_REJECT_METERED) != 0) {
+                // we could silently fail or we can filter the available nets to only give
+                // them those they have access to.  Chose the more useful
+                networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+            }
+        }
+
         if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
             throw new IllegalArgumentException("Bad timeout specified");
         }
-        NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities), legacyType, nextNetworkRequestId());
+        NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
+                nextNetworkRequestId());
         if (DBG) log("requestNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.REQUEST);
@@ -5259,12 +4953,13 @@
 
     public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
-            int currentScore) {
+            int currentScore, NetworkMisc networkMisc) {
         enforceConnectivityInternalPermission();
 
         NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(),
             new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
-            new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler);
+            new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,
+            networkMisc);
         if (VDBG) log("registerNetworkAgent " + nai);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
     }
@@ -5665,7 +5360,9 @@
                 // to tell us whether we've already created this network or not.
                 if (networkAgent.isVPN()) {
                     mNetd.createVirtualNetwork(networkAgent.network.netId,
-                            !networkAgent.linkProperties.getDnsServers().isEmpty());
+                            !networkAgent.linkProperties.getDnsServers().isEmpty(),
+                            (networkAgent.networkMisc == null ||
+                                !networkAgent.networkMisc.allowBypass));
                 } else {
                     mNetd.createPhysicalNetwork(networkAgent.network.netId);
                 }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index bae2d22..3a4e2ee 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -28,6 +28,7 @@
 import com.android.server.location.GeofenceProxy;
 import com.android.server.location.GpsLocationProvider;
 import com.android.server.location.GpsMeasurementsProvider;
+import com.android.server.location.GpsNavigationMessageProvider;
 import com.android.server.location.LocationBlacklist;
 import com.android.server.location.LocationFudger;
 import com.android.server.location.LocationProviderInterface;
@@ -60,6 +61,7 @@
 import android.location.GeocoderParams;
 import android.location.Geofence;
 import android.location.IGpsMeasurementsListener;
+import android.location.IGpsNavigationMessageListener;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
 import android.location.ILocationListener;
@@ -159,6 +161,7 @@
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
     private LocationBlacklist mBlacklist;
     private GpsMeasurementsProvider mGpsMeasurementsProvider;
+    private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
 
     // --- fields below are protected by mLock ---
     // Set of providers that are explicitly enabled
@@ -409,6 +412,7 @@
             mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
         }
         mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
+        mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
 
         /*
         Load package name(s) containing location provider support.
@@ -1847,7 +1851,6 @@
         if (!hasLocationAccess) {
             return false;
         }
-
         return mGpsMeasurementsProvider.addListener(listener);
     }
 
@@ -1857,6 +1860,35 @@
     }
 
     @Override
+    public boolean addGpsNavigationMessageListener(
+            IGpsNavigationMessageListener listener,
+            String packageName) {
+        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+        checkResolutionLevelIsSufficientForProviderUse(
+                allowedResolutionLevel,
+                LocationManager.GPS_PROVIDER);
+
+        int uid = Binder.getCallingUid();
+        long identity = Binder.clearCallingIdentity();
+        boolean hasLocationAccess;
+        try {
+            hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        if (!hasLocationAccess) {
+            return false;
+        }
+        return mGpsNavigationMessageProvider.addListener(listener);
+    }
+
+    @Override
+    public boolean removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
+        return mGpsNavigationMessageProvider.removeListener(listener);
+    }
+
+    @Override
     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
         if (provider == null) {
             // throw NullPointerException to remain compatible with previous implementation
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 5cfc49c..86ce961 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -346,7 +346,8 @@
 
         maybeUpdateKeystore(password, userId);
 
-        writeFile(getLockPasswordFilename(userId), mLockPatternUtils.passwordToHash(password));
+        writeFile(getLockPasswordFilename(userId),
+                mLockPatternUtils.passwordToHash(password, userId));
     }
 
     @Override
@@ -391,7 +392,7 @@
                 return true;
             }
             // Compare the hash from the file with the entered password's hash
-            final byte[] hash = mLockPatternUtils.passwordToHash(password);
+            final byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
             final boolean matched = Arrays.equals(stored, hash);
             if (matched && !TextUtils.isEmpty(password)) {
                 maybeUpdateKeystore(password, userId);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 6c3a4b4..50f2ae9 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -775,7 +775,7 @@
                  */
                 try {
                     final String[] vols = NativeDaemonEvent.filterMessageList(
-                            mConnector.executeForList("volume", "list"),
+                            mConnector.executeForList("volume", "list", "broadcast"),
                             VoldResponseCode.VolumeListResult);
                     for (String volstr : vols) {
                         String[] tok = volstr.split(" ");
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index db423b0..362a745 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -25,6 +25,8 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
 import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
@@ -85,6 +87,7 @@
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.InterfaceAddress;
 import java.net.NetworkInterface;
@@ -1947,11 +1950,12 @@
     }
 
     @Override
-    public void createVirtualNetwork(int netId, boolean hasDNS) {
+    public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0");
+            mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
+                    secure ? "1" : "0");
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
@@ -2101,4 +2105,36 @@
     public void removeInterfaceFromLocalNetwork(String iface) {
         modifyInterfaceInNetwork("remove", "local", iface);
     }
+
+    @Override
+    public void blockAddressFamily(int family, int netId, String iface) {
+        modifyAddressFamily("add", family, netId, iface);
+    }
+
+    @Override
+    public void unblockAddressFamily(int family, int netId, String iface) {
+        modifyAddressFamily("remove", family, netId, iface);
+    }
+
+    private void modifyAddressFamily(String action, int family, int netId, String iface) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        final Command cmd = new Command("network", "route", action, netId, iface);
+
+        if (family == AF_INET) {
+            cmd.appendArg(Inet4Address.ANY.getHostAddress() + "/0");
+        } else if (family == AF_INET6) {
+            cmd.appendArg(Inet6Address.ANY.getHostAddress() + "/0");
+        } else {
+            throw new IllegalStateException(family + " is neither " + AF_INET + " nor " + AF_INET6);
+        }
+
+        cmd.appendArg("unreachable");
+
+        try {
+            mConnector.execute(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 87084d5..cb410ef 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -67,12 +67,22 @@
 /**
  * Since phone process can be restarted, this class provides a centralized place
  * that applications can register and be called back from.
+ *
+ * Change-Id: I450c968bda93767554b5188ee63e10c9f43c5aa4 fixes bugs 16148026
+ * and 15973975 by saving the phoneId of the registrant and then using the
+ * phoneId when deciding to to make a callback. This is necessary because
+ * a subId changes from to a dummy value when a SIM is removed and thus won't
+ * compare properly. Because SubscriptionManager.getPhoneId(long subId) handles
+ * the dummy value conversion we properly do the callbacks.
+ *
+ * Eventually we may want to remove the notion of dummy value but for now this
+ * looks like the best approach.
  */
 class TelephonyRegistry extends ITelephonyRegistry.Stub {
     private static final String TAG = "TelephonyRegistry";
-    private static final boolean DBG = false; // STOPSHIP if true
+    private static final boolean DBG = true; // STOPSHIP if true
     private static final boolean DBG_LOC = false; // STOPSHIP if true
-    private static final boolean VDBG = false; // STOPSHIP if true
+    private static final boolean VDBG = true; // STOPSHIP if true
 
     private static class Record {
         String pkgForDebug;
@@ -87,12 +97,14 @@
 
         long subId;
 
+        int phoneId;
+
         boolean isLegacyApp;
 
         @Override
         public String toString() {
             return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid + " subId=" + subId +
-                    " events=" + Integer.toHexString(events) + "}";
+                    " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}";
         }
     }
 
@@ -146,6 +158,8 @@
 
     private long mDefaultSubId;
 
+    private int mDefaultPhoneIdForDefaultSubId;
+
     private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
 
     private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -179,15 +193,19 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_USER_SWITCHED: {
-                    log("MSG_USER_SWITCHED userId=" + msg.arg1);
+                    if (VDBG) log("MSG_USER_SWITCHED userId=" + msg.arg1);
                     int numPhones = TelephonyManager.getDefault().getPhoneCount();
                     for (int sub = 0; sub < numPhones; sub++) {
-                        TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]);
+                        TelephonyRegistry.this.notifyCellLocationUsingSubId(sub,
+                                mCellLocation[sub]);
                     }
                     break;
                 }
                 case MSG_UPDATE_DEFAULT_SUB: {
-                    log("MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId);
+                    if (VDBG) {
+                        log("MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId
+                                + " phoneId=" + mDefaultPhoneIdForDefaultSubId);
+                    }
                     // Default subscription id changed, update the changed default subscription
                     // id in  all the legacy application listener records.
                     synchronized (mRecords) {
@@ -195,6 +213,7 @@
                             // FIXME: Be sure we're using isLegacyApp correctly!
                             if (r.isLegacyApp == true) {
                                 r.subId = mDefaultSubId;
+                                r.phoneId = mDefaultPhoneIdForDefaultSubId;
                             }
                         }
                     }
@@ -208,7 +227,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            log("mBroadcastReceiver: action=" + action);
+            if (VDBG) log("mBroadcastReceiver: action=" + action);
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (DBG) log("onReceive: userHandle=" + userHandle);
@@ -216,7 +235,12 @@
             } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
                 mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
                         SubscriptionManager.getDefaultSubId());
-                if (DBG) log("onReceive: mDefaultSubId=" + mDefaultSubId);
+                mDefaultPhoneIdForDefaultSubId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
+                        SubscriptionManager.getPhoneId(mDefaultSubId));
+                if (DBG) {
+                    log("onReceive: mDefaultSubId=" + mDefaultSubId
+                            + " mDefaultPhoneIdForDefaultSubId=" + mDefaultPhoneIdForDefaultSubId);
+                }
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
             }
         }
@@ -236,8 +260,9 @@
         mBatteryStats = BatteryStatsService.getService();
         mConnectedApns = new ArrayList<String>();
 
-        // Initialize default subscription to be used for single standby.
+        // Initialize default subId and its phoneId.
         mDefaultSubId = SubscriptionManager.getDefaultSubId();
+        mDefaultPhoneIdForDefaultSubId = SubscriptionManager.getPhoneId(mDefaultSubId);
 
         int numPhones = TelephonyManager.getDefault().getPhoneCount();
         if (DBG) log("TelephonyRegistor: ctor numPhones=" + numPhones);
@@ -310,9 +335,10 @@
             boolean notifyNow, long subId, boolean isLegacyApp) {
         int callerUid = UserHandle.getCallingUserId();
         int myUid = UserHandle.myUserId();
-        if (true /*VDBG*/) {
+        int phoneId = SubscriptionManager.getPhoneId(subId);
+        if (VDBG) {
             log("listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
-                + " notifyNow=" + notifyNow + " subId=" + subId
+                + " notifyNow=" + notifyNow + " subId=" + subId + " phoneId=" + phoneId
                 + " isLegacyApp=" + isLegacyApp
                 + " myUid=" + myUid
                 + " callerUid=" + callerUid);
@@ -339,29 +365,33 @@
                     r.pkgForDebug = pkgForDebug;
                     r.callerUid = callerUid;
                     r.subId = subId;
+                    r.phoneId = phoneId;
                     r.isLegacyApp = isLegacyApp;
                     // Legacy applications pass invalid subId(-1), based on
                     // the received subId value update the isLegacyApp field
                     if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) {
                         r.subId = mDefaultSubId;
-                        r.isLegacyApp = true; // r.subId is to be update when default changes.
+                        r.phoneId = mDefaultPhoneIdForDefaultSubId;
+                        r.isLegacyApp = true; // subId & phoneId are updated when default changes.
                     }
                     if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
                         r.subId = mDefaultSubId;
-                        r.isLegacyApp = true; // r.subId is to be update when default changes.
-                        if (true/*DBG*/) log("listen: DEFAULT_SUB_ID");
+                        r.phoneId = mDefaultPhoneIdForDefaultSubId;
+                        r.isLegacyApp = true; // subId & phoneId are updated when default changes.
+                        if (DBG) log("listen: DEFAULT_SUB_ID");
                     }
                     mRecords.add(r);
-                    if (true/*DBG*/) log("listen: add new record");
+                    if (DBG) log("listen: add new record");
                 }
-                int phoneId = SubscriptionManager.getPhoneId(subId);
                 r.events = events;
-                if (true/*DBG*/) log("listen: set events record=" + r + " subId=" + subId + " phoneId=" + phoneId);
-                toStringLogSSC("listen");
+                if (DBG) {
+                    log("listen: r=" + r + " subId=" + subId + " phoneId=" + phoneId);
+                }
+                if (VDBG) toStringLogSSC("listen");
                 if (notifyNow && validatePhoneId(phoneId)) {
                     if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
                         try {
-                            log("listen: call onSSC state=" + mServiceState[phoneId]);
+                            if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
                             r.callback.onServiceStateChanged(
                                     new ServiceState(mServiceState[phoneId]));
                         } catch (RemoteException ex) {
@@ -516,7 +546,7 @@
         if (!checkNotifyPermission("notifyCallState()")) {
             return;
         }
-        if (true /*VDBG*/) {
+        if (VDBG) {
             log("notifyCallStateUsingSubId: subId=" + subId
                 + " state=" + state + " incomingNumber=" + incomingNumber);
         }
@@ -527,8 +557,8 @@
                 mCallIncomingNumber[phoneId] = incomingNumber;
                 for (Record r : mRecords) {
                     if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
-                        (r.subId == subId) && (r.isLegacyApp == false)) {
-                        // FIXME: why isLegacyApp false?
+                            (r.phoneId == phoneId) &&
+                            (r.isLegacyApp == false)) { // FIXME: why isLegacyApp false?
                         try {
                             r.callback.onCallStateChanged(state, incomingNumber);
                         } catch (RemoteException ex) {
@@ -552,27 +582,32 @@
         }
         if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
             subId = mDefaultSubId;
-            log("notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
+            if (VDBG) log("notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
         }
         synchronized (mRecords) {
             int phoneId = SubscriptionManager.getPhoneId(subId);
-            if (true/*VDBG*/) {
+            if (VDBG) {
                 log("notifyServiceStateUsingSubId: subId=" + subId + " phoneId=" + phoneId
                     + " state=" + state);
             }
             if (validatePhoneId(phoneId)) {
                 mServiceState[phoneId] = state;
                 logServiceStateChanged("notifyServiceStateUsingSubId", subId, phoneId, state);
-                toStringLogSSC("notifyServiceStateUsingSubId");
+                if (VDBG) toStringLogSSC("notifyServiceStateUsingSubId");
 
                 for (Record r : mRecords) {
-                    log("notifyServiceStateUsingSubId: r.events=0x" + Integer.toHexString(r.events) + " r.subId=" + r.subId + " subId=" + subId + " state=" + state);
-                    // FIXME: use DEFAULT_SUB_ID instead??
+                    if (VDBG) {
+                        log("notifyServiceStateUsingSubId: r=" + r + " subId=" + subId
+                                + " phoneId=" + phoneId + " state=" + state);
+                    }
                     if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
-                            (r.subId == subId)) {
+                        (r.phoneId == phoneId)) {
                         try {
-                            log("notifyServiceStateUsingSubId: call onSSC subId=" + subId
-                                    + " state=" + state);
+                            if (DBG) {
+                                log("notifyServiceStateUsingSubId: callback.onSSC r=" + r
+                                        + " subId=" + subId + " phoneId=" + phoneId
+                                        + " state=" + state);
+                            }
                             r.callback.onServiceStateChanged(new ServiceState(state));
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
@@ -595,7 +630,7 @@
         if (!checkNotifyPermission("notifySignalStrength()")) {
             return;
         }
-        if (true/*VDBG*/) {
+        if (VDBG) {
             log("notifySignalStrengthUsingSubId: subId=" + subId
                 + " signalStrength=" + signalStrength);
             toStringLogSSC("notifySignalStrengthUsingSubId");
@@ -603,25 +638,36 @@
         synchronized (mRecords) {
             int phoneId = SubscriptionManager.getPhoneId(subId);
             if (validatePhoneId(phoneId)) {
-                log("notifySignalStrengthUsingSubId: valid phoneId=" + phoneId);
+                if (VDBG) log("notifySignalStrengthUsingSubId: valid phoneId=" + phoneId);
                 mSignalStrength[phoneId] = signalStrength;
                 for (Record r : mRecords) {
-                    log("notifySignalStrengthUsingSubId: r.events=0x" + Integer.toHexString(r.events) + " r.subId=" + r.subId + " subId=" + subId);
+                    if (VDBG) {
+                        log("notifySignalStrengthUsingSubId: r=" + r + " subId=" + subId
+                                + " phoneId=" + phoneId + " ss=" + signalStrength);
+                    }
                     if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
-                        (r.subId == subId)){
+                        (r.phoneId == phoneId)) {
                         try {
-                            log("notifySignalStrengthUsingSubId: callback.onSsS ss=" + signalStrength);
+                            if (DBG) {
+                                log("notifySignalStrengthUsingSubId: callback.onSsS r=" + r
+                                        + " subId=" + subId + " phoneId=" + phoneId
+                                        + " ss=" + signalStrength);
+                            }
                             r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
                     }
                     if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
-                        (r.subId == subId)) {
+                        (r.phoneId == phoneId)) {
                         try {
                             int gsmSignalStrength = signalStrength.getGsmSignalStrength();
                             int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
-                            log("notifySignalStrengthUsingSubId: callback.onSS gsmSS=" + gsmSignalStrength + " ss=" + ss);
+                            if (DBG) {
+                                log("notifySignalStrengthUsingSubId: callback.onSS r=" + r
+                                        + " subId=" + subId + " phoneId=" + phoneId
+                                        + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
+                            }
                             r.callback.onSignalStrengthChanged(ss);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
@@ -714,7 +760,7 @@
                 mMessageWaiting[phoneId] = mwi;
                 for (Record r : mRecords) {
                     if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
-                        (r.subId == subId)) {
+                        (r.phoneId == phoneId)) {
                         try {
                             r.callback.onMessageWaitingIndicatorChanged(mwi);
                         } catch (RemoteException ex) {
@@ -745,7 +791,7 @@
                 mCallForwarding[phoneId] = cfi;
                 for (Record r : mRecords) {
                     if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
-                        (r.subId == subId)) {
+                        (r.phoneId == phoneId)) {
                         try {
                             r.callback.onCallForwardingIndicatorChanged(cfi);
                         } catch (RemoteException ex) {
@@ -842,7 +888,7 @@
                 }
                 for (Record r : mRecords) {
                     if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
-                            (r.subId == subId)) {
+                            (r.phoneId == phoneId)) {
                         try {
                             log("Notify data connection state changed on sub: " +
                                     subId);
@@ -1092,8 +1138,7 @@
             pw.println("  mDcRtInfo=" + mDcRtInfo);
             pw.println("registrations: count=" + recordCount);
             for (Record r : mRecords) {
-                pw.println("  " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
-                pw.println("is Legacy = " + r.isLegacyApp + " subId = " + r.subId);
+                pw.println("  " + r);
             }
         }
     }
@@ -1360,6 +1405,7 @@
                     i = 0;
                 }
             } while (i != next);
+            log(prompt + ": ----------------");
         }
     }
 }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 248a303..20f6f1c 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -55,6 +55,7 @@
 public class VibratorService extends IVibratorService.Stub
         implements InputManager.InputDeviceListener {
     private static final String TAG = "VibratorService";
+    private static final boolean DEBUG = false;
 
     private final LinkedList<Vibration> mVibrations;
     private Vibration mCurrentVibration;
@@ -205,6 +206,7 @@
         }
     }
 
+    @Override // Binder call
     public boolean hasVibrator() {
         return doVibratorExists();
     }
@@ -220,6 +222,7 @@
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
     }
 
+    @Override // Binder call
     public void vibrate(int uid, String opPkg, long milliseconds, int usageHint,
             IBinder token) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
@@ -237,6 +240,10 @@
             return;
         }
 
+        if (DEBUG) {
+            Slog.d(TAG, "Vibrating for " + milliseconds + " ms.");
+        }
+
         Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg);
 
         final long ident = Binder.clearCallingIdentity();
@@ -262,6 +269,7 @@
         return true;
     }
 
+    @Override // Binder call
     public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
             int usageHint, IBinder token) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
@@ -272,13 +280,13 @@
         // so wakelock calls will succeed
         long identity = Binder.clearCallingIdentity();
         try {
-            if (false) {
+            if (DEBUG) {
                 String s = "";
                 int N = pattern.length;
                 for (int i=0; i<N; i++) {
                     s += " " + pattern[i];
                 }
-                Slog.i(TAG, "vibrating with pattern: " + s);
+                Slog.d(TAG, "Vibrating with pattern:" + s);
             }
 
             // we're running in the server so we can't fail
@@ -314,6 +322,7 @@
         }
     }
 
+    @Override // Binder call
     public void cancelVibrate(IBinder token) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.VIBRATE,
@@ -325,6 +334,9 @@
             synchronized (mVibrations) {
                 final Vibration vib = removeVibrationLocked(token);
                 if (vib == mCurrentVibration) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Canceling vibration.");
+                    }
                     doCancelVibrateLocked();
                     startNextVibrationLocked();
                 }
@@ -336,6 +348,7 @@
     }
 
     private final Runnable mVibrationRunnable = new Runnable() {
+        @Override
         public void run() {
             synchronized (mVibrations) {
                 doCancelVibrateLocked();
@@ -516,6 +529,9 @@
 
     private void doVibratorOn(long millis, int uid, int usageHint) {
         synchronized (mInputDeviceVibrators) {
+            if (DEBUG) {
+                Slog.d(TAG, "Turning vibrator on for " + millis + " ms.");
+            }
             try {
                 mBatteryStatsService.noteVibratorOn(uid, millis);
                 mCurVibUid = uid;
@@ -536,6 +552,9 @@
 
     private void doVibratorOff() {
         synchronized (mInputDeviceVibrators) {
+            if (DEBUG) {
+                Slog.d(TAG, "Turning vibrator off.");
+            }
             if (mCurVibUid >= 0) {
                 try {
                     mBatteryStatsService.noteVibratorOff(mCurVibUid);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dcb4f18..d7b2a98 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -46,8 +46,8 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-
 import android.util.SparseIntArray;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
@@ -222,7 +222,11 @@
 
 public final class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
+
     private static final String USER_DATA_DIR = "/data/user/";
+    // 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;
@@ -354,6 +358,8 @@
     static final int ALLOW_NON_FULL_IN_PROFILE = 1;
     static final int ALLOW_FULL_ONLY = 2;
 
+    static final int LAST_PREBOOT_DELIVERED_FILE_VERSION = 10000;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -1152,6 +1158,8 @@
     static final int UPDATE_TIME = 41;
     static final int SYSTEM_USER_START_MSG = 42;
     static final int SYSTEM_USER_CURRENT_MSG = 43;
+    static final int ENTER_ANIMATION_COMPLETE_MSG = 44;
+    static final int ENABLE_SCREEN_AFTER_BOOT_MSG = 45;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1807,6 +1815,22 @@
                 mSystemServiceManager.switchUser(msg.arg1);
                 break;
             }
+            case ENTER_ANIMATION_COMPLETE_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    ActivityRecord r = ActivityRecord.forToken((IBinder) msg.obj);
+                    if (r != null && r.app != null && r.app.thread != null) {
+                        try {
+                            r.app.thread.scheduleEnterAnimationComplete(r.appToken);
+                        } catch (RemoteException e) {
+                        }
+                    }
+                }
+                break;
+            }
+            case ENABLE_SCREEN_AFTER_BOOT_MSG: {
+                enableScreenAfterBoot();
+                break;
+            }
             }
         }
     };
@@ -3079,7 +3103,8 @@
         final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         if (resumed) {
             if (mUsageStatsService != null) {
-                mUsageStatsService.reportEvent(component.realActivity, System.currentTimeMillis(),
+                mUsageStatsService.reportEvent(component.realActivity, component.userId,
+                        System.currentTimeMillis(),
                         UsageStats.Event.MOVE_TO_FOREGROUND);
             }
             synchronized (stats) {
@@ -3087,7 +3112,8 @@
             }
         } else {
             if (mUsageStatsService != null) {
-                mUsageStatsService.reportEvent(component.realActivity, System.currentTimeMillis(),
+                mUsageStatsService.reportEvent(component.realActivity, component.userId,
+                        System.currentTimeMillis(),
                         UsageStats.Event.MOVE_TO_BACKGROUND);
             }
             synchronized (stats) {
@@ -3554,13 +3580,22 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
-        if (task == null) {
-            throw new ActivityNotFoundException("Task " + taskId + " not found.");
+        final int callingUid;
+        final String callingPackage;
+        final Intent intent;
+        final int userId;
+        synchronized (this) {
+            final TaskRecord task = recentTaskForIdLocked(taskId);
+            if (task == null) {
+                throw new ActivityNotFoundException("Task " + taskId + " not found.");
+            }
+            callingUid = task.mCallingUid;
+            callingPackage = task.mCallingPackage;
+            intent = task.intent;
+            userId = task.userId;
         }
-        return startActivityInPackage(task.mCallingUid, task.mCallingPackage,
-                task.intent, null, null, null, 0, 0, options, task.userId,
-                null);
+        return startActivityInPackage(callingUid, callingPackage, intent, null, null, null, 0, 0,
+                options, userId, null);
     }
 
     final int startActivityInPackage(int uid, String callingPackage,
@@ -5495,6 +5530,10 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    void postEnableScreenAfterBootLocked() {
+        mHandler.sendEmptyMessage(ENABLE_SCREEN_AFTER_BOOT_MSG);
+    }
+
     void enableScreenAfterBoot() {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
                 SystemClock.uptimeMillis());
@@ -5684,6 +5723,11 @@
     }
 
     @Override
+    public final void notifyEnterAnimationComplete(IBinder token) {
+        mHandler.sendMessage(mHandler.obtainMessage(ENTER_ANIMATION_COMPLETE_MSG, token));
+    }
+
+    @Override
     public String getCallingPackage(IBinder token) {
         synchronized (this) {
             ActivityRecord r = getCallingRecordLocked(token);
@@ -6554,13 +6598,20 @@
     }
 
     void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
-            final int modeFlags, UriPermissionOwner owner) {
+            final int modeFlags, UriPermissionOwner owner, int targetUserId) {
         if (targetPkg == null) {
             throw new NullPointerException("targetPkg");
         }
+        int targetUid;
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        try {
+            targetUid = pm.getPackageUid(targetPkg, targetUserId);
+        } catch (RemoteException ex) {
+            return;
+        }
 
-        int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags,
-                -1);
+        targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags,
+                targetUid);
         if (targetUid < 0) {
             return;
         }
@@ -6604,6 +6655,11 @@
         if (data == null && clip == null) {
             return null;
         }
+        // Default userId for uris in the intent (if they don't specify it themselves)
+        int contentUserHint = intent.getContentUserHint();
+        if (contentUserHint == UserHandle.USER_CURRENT) {
+            contentUserHint = UserHandle.getUserId(callingUid);
+        }
         final IPackageManager pm = AppGlobals.getPackageManager();
         int targetUid;
         if (needed != null) {
@@ -6623,7 +6679,7 @@
             }
         }
         if (data != null) {
-            GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), data);
+            GrantUri grantUri = GrantUri.resolve(contentUserHint, data);
             targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
                     targetUid);
             if (targetUid > 0) {
@@ -6637,7 +6693,7 @@
             for (int i=0; i<clip.getItemCount(); i++) {
                 Uri uri = clip.getItemAt(i).getUri();
                 if (uri != null) {
-                    GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), uri);
+                    GrantUri grantUri = GrantUri.resolve(contentUserHint, uri);
                     targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
                             targetUid);
                     if (targetUid > 0) {
@@ -6711,7 +6767,8 @@
                     | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
                     | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
 
-            grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null);
+            grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null,
+                    UserHandle.getUserId(r.uid));
         }
     }
 
@@ -6888,7 +6945,7 @@
 
     @Override
     public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
-            final int modeFlags, int userId) {
+            final int modeFlags, int sourceUserId, int targetUserId) {
         synchronized(this) {
             UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
             if (owner == null) {
@@ -6908,8 +6965,8 @@
                 throw new IllegalArgumentException("null uri");
             }
 
-            grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(userId, uri, false),
-                    modeFlags, owner);
+            grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(sourceUserId, uri, false),
+                    modeFlags, owner, targetUserId);
         }
     }
 
@@ -9502,13 +9559,17 @@
                 if (r == null) {
                     return false;
                 }
+                int index = r.task.mActivities.lastIndexOf(r);
+                if (index > 0) {
+                    ActivityRecord under = r.task.mActivities.get(index - 1);
+                    under.returningOptions = options;
+                }
                 if (r.changeWindowTranslucency(false)) {
-                    r.task.stack.convertToTranslucent(r, options);
+                    r.task.stack.convertToTranslucent(r);
                     mWindowManager.setAppFullscreen(token, false);
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                     return true;
                 } else {
-                    r.task.stack.mReturningActivityOptions = options;
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                     return false;
                 }
@@ -9930,12 +9991,10 @@
     private static File getCalledPreBootReceiversFile() {
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
-        File fname = new File(systemDir, "called_pre_boots.dat");
+        File fname = new File(systemDir, CALLED_PRE_BOOTS_FILENAME);
         return fname;
     }
 
-    static final int LAST_DONE_VERSION = 10000;
-
     private static ArrayList<ComponentName> readLastDonePreBootReceivers() {
         ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>();
         File file = getCalledPreBootReceiversFile();
@@ -9944,7 +10003,7 @@
             fis = new FileInputStream(file);
             DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048));
             int fvers = dis.readInt();
-            if (fvers == LAST_DONE_VERSION) {
+            if (fvers == LAST_PREBOOT_DELIVERED_FILE_VERSION) {
                 String vers = dis.readUTF();
                 String codename = dis.readUTF();
                 String build = dis.readUTF();
@@ -9973,16 +10032,15 @@
         }
         return lastDoneReceivers;
     }
-    
+
     private static void writeLastDonePreBootReceivers(ArrayList<ComponentName> list) {
         File file = getCalledPreBootReceiversFile();
         FileOutputStream fos = null;
         DataOutputStream dos = null;
         try {
-            Slog.i(TAG, "Writing new set of last done pre-boot receivers...");
             fos = new FileOutputStream(file);
             dos = new DataOutputStream(new BufferedOutputStream(fos, 2048));
-            dos.writeInt(LAST_DONE_VERSION);
+            dos.writeInt(LAST_PREBOOT_DELIVERED_FILE_VERSION);
             dos.writeUTF(android.os.Build.VERSION.RELEASE);
             dos.writeUTF(android.os.Build.VERSION.CODENAME);
             dos.writeUTF(android.os.Build.VERSION.INCREMENTAL);
@@ -10006,11 +10064,92 @@
             }
         }
     }
-    
+
+    private boolean deliverPreBootCompleted(final Runnable onFinishCallback,
+            ArrayList<ComponentName> doneReceivers, int userId) {
+        boolean waitingUpdate = false;
+        Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+        List<ResolveInfo> ris = null;
+        try {
+            ris = AppGlobals.getPackageManager().queryIntentReceivers(
+                    intent, null, 0, userId);
+        } catch (RemoteException e) {
+        }
+        if (ris != null) {
+            for (int i=ris.size()-1; i>=0; i--) {
+                if ((ris.get(i).activityInfo.applicationInfo.flags
+                        &ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    ris.remove(i);
+                }
+            }
+            intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+
+            // For User 0, load the version number. When delivering to a new user, deliver
+            // to all receivers.
+            if (userId == UserHandle.USER_OWNER) {
+                ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
+                for (int i=0; i<ris.size(); i++) {
+                    ActivityInfo ai = ris.get(i).activityInfo;
+                    ComponentName comp = new ComponentName(ai.packageName, ai.name);
+                    if (lastDoneReceivers.contains(comp)) {
+                        // We already did the pre boot receiver for this app with the current
+                        // platform version, so don't do it again...
+                        ris.remove(i);
+                        i--;
+                        // ...however, do keep it as one that has been done, so we don't
+                        // forget about it when rewriting the file of last done receivers.
+                        doneReceivers.add(comp);
+                    }
+                }
+            }
+
+            // If primary user, send broadcast to all available users, else just to userId
+            final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
+                    : new int[] { userId };
+            for (int i = 0; i < ris.size(); i++) {
+                ActivityInfo ai = ris.get(i).activityInfo;
+                ComponentName comp = new ComponentName(ai.packageName, ai.name);
+                doneReceivers.add(comp);
+                intent.setComponent(comp);
+                for (int j=0; j<users.length; j++) {
+                    IIntentReceiver finisher = null;
+                    // On last receiver and user, set up a completion callback
+                    if (i == ris.size() - 1 && j == users.length - 1 && onFinishCallback != null) {
+                        finisher = new IIntentReceiver.Stub() {
+                            public void performReceive(Intent intent, int resultCode,
+                                    String data, Bundle extras, boolean ordered,
+                                    boolean sticky, int sendingUser) {
+                                // The raw IIntentReceiver interface is called
+                                // with the AM lock held, so redispatch to
+                                // execute our code without the lock.
+                                mHandler.post(onFinishCallback);
+                            }
+                        };
+                    }
+                    Slog.i(TAG, "Sending system update to " + intent.getComponent()
+                            + " for user " + users[j]);
+                    broadcastIntentLocked(null, null, intent, null, finisher,
+                            0, null, null, null, AppOpsManager.OP_NONE,
+                            true, false, MY_PID, Process.SYSTEM_UID,
+                            users[j]);
+                    if (finisher != null) {
+                        waitingUpdate = true;
+                    }
+                }
+            }
+        }
+
+        return waitingUpdate;
+    }
+
     public void systemReady(final Runnable goingCallback) {
         synchronized(this) {
             if (mSystemReady) {
-                if (goingCallback != null) goingCallback.run();
+                // If we're done calling all the receivers, run the next "boot phase" passed in
+                // by the SystemServer
+                if (goingCallback != null) {
+                    goingCallback.run();
+                }
                 return;
             }
 
@@ -10031,82 +10170,20 @@
                 if (mWaitingUpdate) {
                     return;
                 }
-                Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
-                List<ResolveInfo> ris = null;
-                try {
-                    ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                            intent, null, 0, 0);
-                } catch (RemoteException e) {
-                }
-                if (ris != null) {
-                    for (int i=ris.size()-1; i>=0; i--) {
-                        if ((ris.get(i).activityInfo.applicationInfo.flags
-                                &ApplicationInfo.FLAG_SYSTEM) == 0) {
-                            ris.remove(i);
+                final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
+                mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
+                    public void run() {
+                        synchronized (ActivityManagerService.this) {
+                            mDidUpdate = true;
                         }
+                        writeLastDonePreBootReceivers(doneReceivers);
+                        showBootMessage(mContext.getText(
+                                R.string.android_upgrading_complete),
+                                false);
+                        systemReady(goingCallback);
                     }
-                    intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+                }, doneReceivers, UserHandle.USER_OWNER);
 
-                    ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
-
-                    final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
-                    for (int i=0; i<ris.size(); i++) {
-                        ActivityInfo ai = ris.get(i).activityInfo;
-                        ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                        if (lastDoneReceivers.contains(comp)) {
-                            // We already did the pre boot receiver for this app with the current
-                            // platform version, so don't do it again...
-                            ris.remove(i);
-                            i--;
-                            // ...however, do keep it as one that has been done, so we don't
-                            // forget about it when rewriting the file of last done receivers.
-                            doneReceivers.add(comp);
-                        }
-                    }
-
-                    final int[] users = getUsersLocked();
-                    for (int i=0; i<ris.size(); i++) {
-                        ActivityInfo ai = ris.get(i).activityInfo;
-                        ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                        doneReceivers.add(comp);
-                        intent.setComponent(comp);
-                        for (int j=0; j<users.length; j++) {
-                            IIntentReceiver finisher = null;
-                            if (i == ris.size()-1 && j == users.length-1) {
-                                finisher = new IIntentReceiver.Stub() {
-                                    public void performReceive(Intent intent, int resultCode,
-                                            String data, Bundle extras, boolean ordered,
-                                            boolean sticky, int sendingUser) {
-                                        // The raw IIntentReceiver interface is called
-                                        // with the AM lock held, so redispatch to
-                                        // execute our code without the lock.
-                                        mHandler.post(new Runnable() {
-                                            public void run() {
-                                                synchronized (ActivityManagerService.this) {
-                                                    mDidUpdate = true;
-                                                }
-                                                writeLastDonePreBootReceivers(doneReceivers);
-                                                showBootMessage(mContext.getText(
-                                                        R.string.android_upgrading_complete),
-                                                        false);
-                                                systemReady(goingCallback);
-                                            }
-                                        });
-                                    }
-                                };
-                            }
-                            Slog.i(TAG, "Sending system update to " + intent.getComponent()
-                                    + " for user " + users[j]);
-                            broadcastIntentLocked(null, null, intent, null, finisher,
-                                    0, null, null, null, AppOpsManager.OP_NONE,
-                                    true, false, MY_PID, Process.SYSTEM_UID,
-                                    users[j]);
-                            if (finisher != null) {
-                                mWaitingUpdate = true;
-                            }
-                        }
-                    }
-                }
                 if (mWaitingUpdate) {
                     return;
                 }
@@ -17139,6 +17216,7 @@
                 }
 
                 if (needStart) {
+                    // Send USER_STARTED broadcast
                     Intent intent = new Intent(Intent.ACTION_USER_STARTED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                             | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -17150,6 +17228,11 @@
 
                 if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
                     if (userId != UserHandle.USER_OWNER) {
+                        // Send PRE_BOOT_COMPLETED broadcasts for this new user
+                        final ArrayList<ComponentName> doneReceivers
+                                = new ArrayList<ComponentName>();
+                        deliverPreBootCompleted(null, doneReceivers, userId);
+
                         Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         broadcastIntentLocked(null, null, intent, null,
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 85f49ed..e528d57 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -130,6 +130,7 @@
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
     ArrayList<Intent> newIntents; // any pending new intents for single-top mode
     ActivityOptions pendingOptions; // most recently given options
+    ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
     UriPermissionOwner uriPermissions; // current special URI access perms.
     ProcessRecord app;      // if non-null, hosting application
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 91bc7e3..4766742 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -211,9 +211,6 @@
     ActivityRecord mTranslucentActivityWaiting = null;
     private ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent =
             new ArrayList<ActivityRecord>();
-    // Options passed from the caller of the convertToTranslucent to the activity that will
-    // appear below it.
-    ActivityOptions mReturningActivityOptions = null;
 
     /**
      * Set when we know we are going to be calling updateConfiguration()
@@ -1052,6 +1049,14 @@
         next.idle = false;
         next.results = null;
         next.newIntents = null;
+
+        if (next.isHomeActivity() && next.isNotResolverActivity()) {
+            ProcessRecord app = next.task.mActivities.get(0).app;
+            if (app != null && app != mService.mHomeProcess) {
+                mService.mHomeProcess = app;
+            }
+        }
+
         if (next.nowVisible) {
             // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
             mStackSupervisor.dismissKeyguard();
@@ -1081,7 +1086,7 @@
         if (next == mLastScreenshotActivity) {
             invalidateLastScreenshot();
         }
-        mReturningActivityOptions = null;
+        next.returningOptions = null;
     }
 
     private void setVisibile(ActivityRecord r, boolean visible) {
@@ -1211,10 +1216,9 @@
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Skipping: already visible at " + r);
                         r.stopFreezingScreenLocked(false);
                         try {
-                            if (mReturningActivityOptions != null && r == top && activityNdx > 0) {
-                                ActivityRecord under = activities.get(activityNdx - 1);
-                                under.app.thread.scheduleOnNewActivityOptions(under.appToken,
-                                        mReturningActivityOptions);
+                            if (r.returningOptions != null) {
+                                r.app.thread.scheduleOnNewActivityOptions(r.appToken,
+                                        r.returningOptions);
                             }
                         } catch(RemoteException e) {
                         }
@@ -1229,7 +1233,7 @@
                                     TAG, "Making visible and scheduling visibility: " + r);
                             try {
                                 if (mTranslucentActivityWaiting != null) {
-                                    r.updateOptionsLocked(mReturningActivityOptions);
+                                    r.updateOptionsLocked(r.returningOptions);
                                     mUndrawnActivitiesBelowTopTranslucent.add(r);
                                 }
                                 setVisibile(r, true);
@@ -1317,10 +1321,9 @@
         }
     }
 
-    void convertToTranslucent(ActivityRecord r, ActivityOptions options) {
+    void convertToTranslucent(ActivityRecord r) {
         mTranslucentActivityWaiting = r;
         mUndrawnActivitiesBelowTopTranslucent.clear();
-        mReturningActivityOptions = options;
         mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
     }
 
@@ -2067,6 +2070,8 @@
         final int rootActivityNdx = task.findEffectiveRootIndex();
         for (int i = numActivities - 1; i > rootActivityNdx; --i ) {
             ActivityRecord target = activities.get(i);
+            if (target.frontOfTask)
+                break;
 
             final int flags = target.info.flags;
             final boolean finishOnTaskLaunch =
@@ -2223,6 +2228,8 @@
         // Do not operate on or below the effective root Activity.
         for (int i = numActivities - 1; i > rootActivityNdx; --i) {
             ActivityRecord target = activities.get(i);
+            if (target.frontOfTask)
+                break;
 
             final int flags = target.info.flags;
             boolean finishOnTaskLaunch = (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
@@ -2575,7 +2582,7 @@
                     + " res=" + resultCode + " data=" + resultData);
             if (resultTo.userId != r.userId) {
                 if (resultData != null) {
-                    resultData.prepareToLeaveUser(r.userId);
+                    resultData.setContentUserHint(r.userId);
                 }
             }
             if (r.info.applicationInfo.uid > 0) {
@@ -3789,7 +3796,9 @@
                 if (r.app == app) {
                     Slog.w(TAG, "  Force finishing activity "
                             + r.intent.getComponent().flattenToShortString());
-                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
+                    // Force the destroy to skip right to removal.
+                    r.app = null;
+                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c6dbfba..48ed5ea 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2176,7 +2176,7 @@
         //mWindowManager.dump();
 
         if (enableScreen) {
-            mService.enableScreenAfterBoot();
+            mService.postEnableScreenAfterBootLocked();
         }
 
         if (activityRemoved) {
@@ -3284,10 +3284,11 @@
                             mLockTaskNotify = new LockTaskNotify(mService.mContext);
                         }
                         mLockTaskNotify.show(true);
+                        mLockTaskIsLocked = msg.arg2 == 0;
                         if (getStatusBarService() != null) {
                             int flags =
                                     StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
-                            if (msg.arg2 != 0) {
+                            if (!mLockTaskIsLocked) {
                                 flags ^= StatusBarManager.DISABLE_HOME
                                         | StatusBarManager.DISABLE_RECENT;
                             }
@@ -3323,7 +3324,7 @@
                             boolean shouldLockKeyguard = Settings.System.getInt(
                                     mService.mContext.getContentResolver(),
                                     Settings.System.LOCK_TO_APP_EXIT_LOCKED) != 0;
-                            if (shouldLockKeyguard) {
+                            if (!mLockTaskIsLocked && shouldLockKeyguard) {
                                 mWindowManager.lockNow(null);
                                 mWindowManager.dismissKeyguard();
                             }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index cdcc74b..4e554eb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -424,11 +424,16 @@
             Intent intent, int resultCode, String data, Bundle extras,
             boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
         // Send the intent to the receiver asynchronously using one-way binder calls.
-        if (app != null && app.thread != null) {
-            // If we have an app thread, do the call through that so it is
-            // correctly ordered with other one-way calls.
-            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                    data, extras, ordered, sticky, sendingUser, app.repProcState);
+        if (app != null) {
+            if (app.thread != null) {
+                // If we have an app thread, do the call through that so it is
+                // correctly ordered with other one-way calls.
+                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+                        data, extras, ordered, sticky, sendingUser, app.repProcState);
+            } else {
+                // Application has died. Receiver doesn't exist.
+                throw new RemoteException("app.thread must not be null");
+            }
         } else {
             receiver.performReceive(intent, resultCode, data, extras, ordered,
                     sticky, sendingUser);
@@ -670,6 +675,7 @@
                             // (local and remote) isn't kept in the mBroadcastHistory.
                             r.resultTo = null;
                         } catch (RemoteException e) {
+                            r.resultTo = null;
                             Slog.w(TAG, "Failure ["
                                     + mQueueName + "] sending broadcast result of "
                                     + r.intent, e);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 69949a4..d6f922f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -74,6 +74,8 @@
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
+    static final boolean IGNORE_RETURN_TO_RECENTS = true;
+
     final int taskId;       // Unique identifier for this task.
     String affinity;        // The affinity name for this task, or null.
     final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
@@ -292,6 +294,9 @@
     }
 
     void setTaskToReturnTo(int taskToReturnTo) {
+        if (IGNORE_RETURN_TO_RECENTS && taskToReturnTo == RECENTS_ACTIVITY_TYPE) {
+            taskToReturnTo = HOME_ACTIVITY_TYPE;
+        }
         mTaskToReturnTo = taskToReturnTo;
     }
 
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 15e3e89..1c26846 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -32,18 +32,23 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.IUserManager;
 import android.os.Parcel;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import java.util.HashSet;
+import java.util.List;
 
 /**
  * Implementation of the clipboard for copy and paste.
@@ -54,6 +59,7 @@
 
     private final Context mContext;
     private final IActivityManager mAm;
+    private final IUserManager mUm;
     private final PackageManager mPm;
     private final AppOpsManager mAppOps;
     private final IBinder mPermissionOwner;
@@ -92,6 +98,7 @@
         mContext = context;
         mAm = ActivityManagerNative.getDefault();
         mPm = context.getPackageManager();
+        mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
         IBinder permOwner = null;
         try {
@@ -161,32 +168,81 @@
                 return;
             }
             checkDataOwnerLocked(clip, callingUid);
-            clearActiveOwnersLocked();
-            PerUserClipboard clipboard = getClipboard();
-            clipboard.primaryClip = clip;
-            final long ident = Binder.clearCallingIdentity();
-            final int n = clipboard.primaryClipListeners.beginBroadcast();
-            try {
-                for (int i = 0; i < n; i++) {
+            final int userId = UserHandle.getUserId(callingUid);
+            PerUserClipboard clipboard = getClipboard(userId);
+            revokeUris(clipboard);
+            setPrimaryClipInternal(clipboard, clip);
+            List<UserInfo> related = getRelatedProfiles(userId);
+            if (related != null) {
+                int size = related.size();
+                if (size > 1) { // Related profiles list include the current profile.
+                    boolean canCopy = false;
                     try {
-                        ListenerInfo li = (ListenerInfo)
-                                clipboard.primaryClipListeners.getBroadcastCookie(i);
-                        if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid,
-                                li.mPackageName) == AppOpsManager.MODE_ALLOWED) {
-                            clipboard.primaryClipListeners.getBroadcastItem(i)
-                                    .dispatchPrimaryClipChanged();
-                        }
+                        canCopy = !mUm.getUserRestrictions(userId).getBoolean(
+                                UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
                     } catch (RemoteException e) {
-                        // The RemoteCallbackList will take care of removing
-                        // the dead object for us.
+                        Slog.e(TAG, "Remote Exception calling UserManager: " + e);
+                    }
+                    // Copy clip data to related users if allowed. If disallowed, then remove
+                    // primary clip in related users to prevent pasting stale content.
+                    if (!canCopy) {
+                        clip = null;
+                    } else {
+                        clip.fixUrisLight(userId);
+                    }
+                    for (int i = 0; i < size; i++) {
+                        int id = related.get(i).id;
+                        if (id != userId) {
+                            setPrimaryClipInternal(getClipboard(id), clip);
+                        }
                     }
                 }
-            } finally {
-                clipboard.primaryClipListeners.finishBroadcast();
-                Binder.restoreCallingIdentity(ident);
             }
         }
     }
+
+    List<UserInfo> getRelatedProfiles(int userId) {
+        final List<UserInfo> related;
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            related = mUm.getProfiles(userId, true);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote Exception calling UserManager: " + e);
+            return null;
+        } finally{
+            Binder.restoreCallingIdentity(origId);
+        }
+        return related;
+    }
+
+    void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) {
+        clipboard.activePermissionOwners.clear();
+        if (clip == null && clipboard.primaryClip == null) {
+            return;
+        }
+        clipboard.primaryClip = clip;
+        final long ident = Binder.clearCallingIdentity();
+        final int n = clipboard.primaryClipListeners.beginBroadcast();
+        try {
+            for (int i = 0; i < n; i++) {
+                try {
+                    ListenerInfo li = (ListenerInfo)
+                            clipboard.primaryClipListeners.getBroadcastCookie(i);
+                    if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid,
+                            li.mPackageName) == AppOpsManager.MODE_ALLOWED) {
+                        clipboard.primaryClipListeners.getBroadcastItem(i)
+                                .dispatchPrimaryClipChanged();
+                    }
+                } catch (RemoteException e) {
+                    // The RemoteCallbackList will take care of removing
+                    // the dead object for us.
+                }
+            }
+        } finally {
+            clipboard.primaryClipListeners.finishBroadcast();
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
     
     public ClipData getPrimaryClip(String pkg) {
         synchronized (this) {
@@ -257,7 +313,8 @@
         try {
             // This will throw SecurityException for us.
             mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri),
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION, resolveUserId(uri, uid));
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                    ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid)));
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -281,26 +338,26 @@
         }
     }
 
-    private final void grantUriLocked(Uri uri, String pkg) {
+    private final void grantUriLocked(Uri uri, String pkg, int userId) {
         long ident = Binder.clearCallingIdentity();
         try {
+            int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId);
+            uri = ContentProvider.getUriWithoutUserId(uri);
             mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg,
-                    ContentProvider.getUriWithoutUserId(uri),
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
-                    resolveUserId(uri, Process.myUid()));
+                    uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId);
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    private final void grantItemLocked(ClipData.Item item, String pkg) {
+    private final void grantItemLocked(ClipData.Item item, String pkg, int userId) {
         if (item.getUri() != null) {
-            grantUriLocked(item.getUri(), pkg);
+            grantUriLocked(item.getUri(), pkg, userId);
         }
         Intent intent = item.getIntent();
         if (intent != null && intent.getData() != null) {
-            grantUriLocked(intent.getData(), pkg);
+            grantUriLocked(intent.getData(), pkg, userId);
         }
     }
 
@@ -326,19 +383,21 @@
         if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
             final int N = clipboard.primaryClip.getItemCount();
             for (int i=0; i<N; i++) {
-                grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg);
+                grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid));
             }
             clipboard.activePermissionOwners.add(pkg);
         }
     }
 
     private final void revokeUriLocked(Uri uri) {
+        int userId = ContentProvider.getUserIdFromUri(uri,
+                UserHandle.getUserId(Binder.getCallingUid()));
         long ident = Binder.clearCallingIdentity();
         try {
-            mAm.revokeUriPermissionFromOwner(mPermissionOwner,
-                    ContentProvider.getUriWithoutUserId(uri),
+            uri = ContentProvider.getUriWithoutUserId(uri);
+            mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri,
                     Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
-                    resolveUserId(uri, Process.myUid()));
+                    userId);
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -355,9 +414,7 @@
         }
     }
 
-    private final void clearActiveOwnersLocked() {
-        PerUserClipboard clipboard = getClipboard();
-        clipboard.activePermissionOwners.clear();
+    private final void revokeUris(PerUserClipboard clipboard) {
         if (clipboard.primaryClip == null) {
             return;
         }
@@ -366,8 +423,4 @@
             revokeItemLocked(clipboard.primaryClip.getItemAt(i));
         }
     }
-
-    private final int resolveUserId(Uri uri, int uid) {
-        return ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid));
-    }
 }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 10bdba0..403713d 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -21,6 +21,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
+import android.net.NetworkMisc;
 import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.Messenger;
@@ -44,6 +45,7 @@
     public NetworkCapabilities networkCapabilities;
     public int currentScore;
     public final NetworkMonitor networkMonitor;
+    public final NetworkMisc networkMisc;
 
     // The list of NetworkRequests being satisfied by this Network.
     public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
@@ -53,8 +55,8 @@
     public final AsyncChannel asyncChannel;
 
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, int netId, NetworkInfo info,
-            LinkProperties lp, NetworkCapabilities nc, int score, Context context,
-            Handler handler) {
+            LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
+            NetworkMisc misc) {
         this.messenger = messenger;
         asyncChannel = ac;
         network = new Network(netId);
@@ -63,6 +65,7 @@
         networkCapabilities = nc;
         currentScore = score;
         networkMonitor = new NetworkMonitor(context, handler, this);
+        networkMisc = misc;
     }
 
     public void addRequest(NetworkRequest networkRequest) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index d948942..fa8626f 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -27,7 +27,6 @@
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
@@ -95,7 +94,6 @@
 
     private final INetworkManagementService mNMService;
     private final INetworkStatsService mStatsService;
-    private final IConnectivityManager mConnService;
     private Looper mLooper;
 
     private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
@@ -132,11 +130,10 @@
                                          // when RNDIS is enabled
 
     public Tethering(Context context, INetworkManagementService nmService,
-            INetworkStatsService statsService, IConnectivityManager connService, Looper looper) {
+            INetworkStatsService statsService, Looper looper) {
         mContext = context;
         mNMService = nmService;
         mStatsService = statsService;
-        mConnService = connService;
         mLooper = looper;
 
         mPublicSync = new Object();
@@ -176,6 +173,12 @@
         mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2;
     }
 
+    // We can't do this once in the Tethering() constructor and cache the value, because the
+    // CONNECTIVITY_SERVICE is registered only after the Tethering() constructor has completed.
+    private ConnectivityManager getConnectivityManager() {
+        return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+    }
+
     void updateConfiguration() {
         String[] tetherableUsbRegexs = mContext.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_usb_regexs);
@@ -367,11 +370,7 @@
     // TODO - move all private methods used only by the state machine into the state machine
     // to clarify what needs synchronized protection.
     private void sendTetherStateChangedBroadcast() {
-        try {
-            if (!mConnService.isTetheringSupported()) return;
-        } catch (RemoteException e) {
-            return;
-        }
+        if (!getConnectivityManager().isTetheringSupported()) return;
 
         ArrayList<String> availableList = new ArrayList<String>();
         ArrayList<String> activeList = new ArrayList<String>();
@@ -1188,11 +1187,8 @@
                 int result = PhoneConstants.APN_REQUEST_FAILED;
                 String enableString = enableString(apnType);
                 if (enableString == null) return false;
-                try {
-                    result = mConnService.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                            enableString, new Binder());
-                } catch (Exception e) {
-                }
+                result = getConnectivityManager().startUsingNetworkFeature(
+                        ConnectivityManager.TYPE_MOBILE, enableString);
                 switch (result) {
                 case PhoneConstants.APN_ALREADY_ACTIVE:
                 case PhoneConstants.APN_REQUEST_STARTED:
@@ -1213,12 +1209,8 @@
                 // ignore pending renewal requests
                 ++mCurrentConnectionSequence;
                 if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) {
-                    try {
-                        mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                                enableString(mMobileApnReserved));
-                    } catch (Exception e) {
-                        return false;
-                    }
+                    getConnectivityManager().stopUsingNetworkFeature(
+                            ConnectivityManager.TYPE_MOBILE, enableString(mMobileApnReserved));
                     mMobileApnReserved = ConnectivityManager.TYPE_NONE;
                 }
                 return true;
@@ -1281,10 +1273,8 @@
                     }
 
                     for (Integer netType : mUpstreamIfaceTypes) {
-                        NetworkInfo info = null;
-                        try {
-                            info = mConnService.getNetworkInfo(netType.intValue());
-                        } catch (RemoteException e) { }
+                        NetworkInfo info =
+                                getConnectivityManager().getNetworkInfo(netType.intValue());
                         if ((info != null) && info.isConnected()) {
                             upType = netType.intValue();
                             break;
@@ -1322,10 +1312,8 @@
                         sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
                     }
                 } else {
-                    LinkProperties linkProperties = null;
-                    try {
-                        linkProperties = mConnService.getLinkPropertiesForType(upType);
-                    } catch (RemoteException e) { }
+                    LinkProperties linkProperties =
+                            getConnectivityManager().getLinkProperties(upType);
                     if (linkProperties != null) {
                         // Find the interface with the default IPv4 route. It may be the
                         // interface described by linkProperties, or one of the interfaces
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7b68d55..0a8ca6a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -17,6 +17,8 @@
 package com.android.server.connectivity;
 
 import static android.Manifest.permission.BIND_VPN_SERVICE;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
 
 import android.app.AppGlobals;
 import android.app.Notification;
@@ -48,6 +50,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkMisc;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.UidRange;
@@ -77,6 +80,7 @@
 import com.android.server.net.BaseNetworkObserver;
 
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
@@ -105,6 +109,8 @@
     private String mPackage;
     private int mOwnerUID;
     private String mInterface;
+    private boolean mAllowIPv4;
+    private boolean mAllowIPv6;
     private Connection mConnection;
     private LegacyVpnRunner mLegacyVpnRunner;
     private PendingIntent mStatusIntent;
@@ -305,6 +311,7 @@
     private void agentConnect() {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName(mInterface);
+
         boolean hasDefaultRoute = false;
         for (RouteInfo route : mConfig.routes) {
             lp.addRoute(route);
@@ -315,11 +322,19 @@
         } else {
             mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
         }
+
         if (mConfig.dnsServers != null) {
             for (String dnsServer : mConfig.dnsServers) {
-                lp.addDnsServer(InetAddress.parseNumericAddress(dnsServer));
+                InetAddress address = InetAddress.parseNumericAddress(dnsServer);
+                lp.addDnsServer(address);
+                if (address instanceof Inet4Address) {
+                    mAllowIPv4 = true;
+                } else {
+                    mAllowIPv6 = true;
+                }
             }
         }
+
         // Concatenate search domains into a string.
         StringBuilder buffer = new StringBuilder();
         if (mConfig.searchDomains != null) {
@@ -328,12 +343,17 @@
             }
         }
         lp.setDomains(buffer.toString().trim());
+
         mNetworkInfo.setIsAvailable(true);
         mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+
+        NetworkMisc networkMisc = new NetworkMisc();
+        networkMisc.allowBypass = mConfig.allowBypass;
+
         long token = Binder.clearCallingIdentity();
         try {
             mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE,
-                    mNetworkInfo, mNetworkCapabilities, lp, 0) {
+                    mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) {
                             public void unwanted() {
                                 // We are user controlled, not driven by NetworkRequest.
                             };
@@ -341,6 +361,14 @@
         } finally {
             Binder.restoreCallingIdentity(token);
         }
+
+        if (!mAllowIPv4) {
+            mNetworkAgent.blockAddressFamily(AF_INET);
+        }
+        if (!mAllowIPv6) {
+            mNetworkAgent.blockAddressFamily(AF_INET6);
+        }
+
         addVpnUserLocked(mUserId);
         // If we are owner assign all Restricted Users to this VPN
         if (mUserId == UserHandle.USER_OWNER) {
@@ -426,6 +454,8 @@
         NetworkAgent oldNetworkAgent = mNetworkAgent;
         mNetworkAgent = null;
         List<UidRange> oldUsers = mVpnUsers;
+        boolean oldAllowIPv4 = mAllowIPv4;
+        boolean oldAllowIPv6 = mAllowIPv6;
 
         // Configure the interface. Abort if any of these steps fails.
         ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
@@ -458,6 +488,9 @@
 
             // Set up forwarding and DNS rules.
             mVpnUsers = new ArrayList<UidRange>();
+            mAllowIPv4 = mConfig.allowIPv4;
+            mAllowIPv6 = mConfig.allowIPv6;
+
             agentConnect();
 
             if (oldConnection != null) {
@@ -470,6 +503,13 @@
             if (oldInterface != null && !oldInterface.equals(interfaze)) {
                 jniReset(oldInterface);
             }
+
+            try {
+                IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking);
+            } catch (IOException e) {
+                throw new IllegalStateException(
+                        "Cannot set tunnel's fd as blocking=" + config.blocking, e);
+            }
         } catch (RuntimeException e) {
             IoUtils.closeQuietly(tun);
             agentDisconnect();
@@ -479,12 +519,11 @@
             mVpnUsers = oldUsers;
             mNetworkAgent = oldNetworkAgent;
             mInterface = oldInterface;
+            mAllowIPv4 = oldAllowIPv4;
+            mAllowIPv6 = oldAllowIPv6;
             throw e;
         }
         Log.i(TAG, "Established by " + config.user + " on " + mInterface);
-
-        // TODO: ensure that contract class eventually marks as connected
-        updateState(DetailedState.AUTHENTICATING, "establish");
         return tun;
     }
 
@@ -1165,6 +1204,8 @@
                     // Now INetworkManagementEventObserver is watching our back.
                     mInterface = mConfig.interfaze;
                     mVpnUsers = new ArrayList<UidRange>();
+                    mAllowIPv4 = mConfig.allowIPv4;
+                    mAllowIPv6 = mConfig.allowIPv6;
 
                     agentConnect();
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2737646..b9acea5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1367,7 +1367,7 @@
             }
             if (mContext.checkCallingPermission(
                     android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
-                    != PackageManager.PERMISSION_GRANTED) {
+                    == PackageManager.PERMISSION_GRANTED) {
                 return true;
             }
             return canProjectSecureVideo(projection);
@@ -1385,7 +1385,7 @@
             }
             return mContext.checkCallingPermission(
                     android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
-                    != PackageManager.PERMISSION_GRANTED;
+                    == PackageManager.PERMISSION_GRANTED;
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 09221a3e..d0e4b33 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -566,8 +566,10 @@
         // Apply dimming by at least some minimum amount when user activity
         // timeout is about to expire.
         if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
-            brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
-                    mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
+            if (brightness > mScreenBrightnessRangeMinimum) {
+                brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
+                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
+            }
             if (!mAppliedDimming) {
                 slowChange = false;
             }
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 107a6f6..b894304 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -45,7 +45,6 @@
 import android.provider.Settings;
 import android.service.dreams.DreamManagerInternal;
 import android.service.dreams.DreamService;
-import android.service.dreams.IDozeHardware;
 import android.service.dreams.IDreamManager;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -75,7 +74,6 @@
     private final PowerManager mPowerManager;
     private final PowerManagerInternal mPowerManagerInternal;
     private final PowerManager.WakeLock mDozeWakeLock;
-    private final McuHal mMcuHal; // synchronized on self
 
     private Binder mCurrentDreamToken;
     private ComponentName mCurrentDreamName;
@@ -86,7 +84,6 @@
     private boolean mCurrentDreamIsWaking;
     private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
     private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
-    private DozeHardwareWrapper mCurrentDreamDozeHardware;
 
     public DreamManagerService(Context context) {
         super(context);
@@ -97,11 +94,6 @@
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
         mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
-
-        mMcuHal = McuHal.open();
-        if (mMcuHal != null) {
-            mMcuHal.reset();
-        }
     }
 
     @Override
@@ -130,9 +122,6 @@
     private void dumpInternal(PrintWriter pw) {
         pw.println("DREAM MANAGER (dumpsys dreams)");
         pw.println();
-
-        pw.println("mMcuHal=" + mMcuHal);
-        pw.println();
         pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
         pw.println("mCurrentDreamName=" + mCurrentDreamName);
         pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
@@ -143,7 +132,6 @@
         pw.println("mCurrentDreamDozeScreenState="
                 + Display.stateToString(mCurrentDreamDozeScreenState));
         pw.println("mCurrentDreamDozeScreenBrightness=" + mCurrentDreamDozeScreenBrightness);
-        pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware);
         pw.println("getDozeComponent()=" + getDozeComponent());
         pw.println();
 
@@ -259,17 +247,6 @@
         }
     }
 
-    private IDozeHardware getDozeHardwareInternal(IBinder token) {
-        synchronized (mLock) {
-            if (mCurrentDreamToken == token && mCurrentDreamCanDoze
-                    && mCurrentDreamDozeHardware == null && mMcuHal != null) {
-                mCurrentDreamDozeHardware = new DozeHardwareWrapper();
-                return mCurrentDreamDozeHardware;
-            }
-            return null;
-        }
-    }
-
     private ComponentName chooseDreamForUser(boolean doze, int userId) {
         if (doze) {
             ComponentName dozeComponent = getDozeComponent();
@@ -420,10 +397,6 @@
         }
         mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
         mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
-        if (mCurrentDreamDozeHardware != null) {
-            mCurrentDreamDozeHardware.release();
-            mCurrentDreamDozeHardware = null;
-        }
     }
 
     private void checkPermission(String permission) {
@@ -642,21 +615,6 @@
                 Binder.restoreCallingIdentity(ident);
             }
         }
-
-        @Override // Binder call
-        public IDozeHardware getDozeHardware(IBinder token) {
-            // Requires no permission, called by Dream from an arbitrary process.
-            if (token == null) {
-                throw new IllegalArgumentException("token must not be null");
-            }
-
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                return getDozeHardwareInternal(token);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
     }
 
     private final class LocalService extends DreamManagerInternal {
@@ -676,40 +634,6 @@
         }
     }
 
-    private final class DozeHardwareWrapper extends IDozeHardware.Stub {
-        private boolean mReleased;
-
-        public void release() {
-            synchronized (mMcuHal) {
-                if (!mReleased) {
-                    mReleased = true;
-                    mMcuHal.reset();
-                }
-            }
-        }
-
-        @Override // Binder call
-        public byte[] sendMessage(String msg, byte[] arg) {
-            if (msg == null) {
-                throw new IllegalArgumentException("msg must not be null");
-            }
-
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                synchronized (mMcuHal) {
-                    if (mReleased) {
-                        Slog.w(TAG, "Ignoring message to MCU HAL because the dream "
-                                + "has already ended: " + msg);
-                        return null;
-                    }
-                    return mMcuHal.sendMessage(msg, arg);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-    }
-
     private final Runnable mSystemPropertiesChanged = new Runnable() {
         @Override
         public void run() {
diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java
deleted file mode 100644
index 1dc79c7..0000000
--- a/services/core/java/com/android/server/dreams/McuHal.java
+++ /dev/null
@@ -1,46 +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.server.dreams;
-
-import android.service.dreams.DozeHardware;
-
-/**
- * Provides access to the low-level microcontroller hardware abstraction layer.
- */
-final class McuHal {
-    private final long mPtr;
-
-    private static native long nativeOpen();
-    private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg);
-
-    private McuHal(long ptr) {
-        mPtr = ptr;
-    }
-
-    public static McuHal open() {
-        long ptr = nativeOpen();
-        return ptr != 0 ? new McuHal(ptr) : null;
-    }
-
-    public void reset() {
-        sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF);
-    }
-
-    public byte[] sendMessage(String msg, byte[] arg) {
-        return nativeSendMessage(mPtr, msg, arg);
-    }
-}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 432424b..f3d570e 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -23,6 +23,8 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
+
 /**
  * Handles CEC command &lt;Active Source&gt;.
  * <p>
@@ -54,44 +56,45 @@
     /**
      * Handles the incoming active source command.
      *
-     * @param activeAddress logical address of the device to be the active source
-     * @param activePath routing path of the device to be the active source
+     * @param newActive new active source information
      */
-    void process(int activeAddress, int activePath) {
+    void process(ActiveSource newActive) {
         // Seq #17
         HdmiCecLocalDeviceTv tv = mSource;
-        if (getSourcePath() == activePath && tv.getActiveSource() == getSourceAddress()) {
+        ActiveSource activeSource = tv.getActiveSource();
+        if (activeSource.equals(newActive)) {
             invokeCallback(HdmiControlManager.RESULT_SUCCESS);
             return;
         }
-        HdmiCecDeviceInfo device = mService.getDeviceInfo(activeAddress);
+        HdmiCecDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
         if (device == null) {
-            tv.startNewDeviceAction(activeAddress, activePath);
+            tv.startNewDeviceAction(newActive);
         }
 
-        int currentActive = tv.getActiveSource();
-        int currentPath = tv.getActivePath();
+        ActiveSource current = tv.getActiveSource();
         if (!tv.isProhibitMode()) {
-            tv.updateActiveSource(activeAddress, activePath);
-            if (currentActive != activeAddress && currentPath != activePath) {
-                tv.updateActivePortId(mService.pathToPortId(activePath));
+            tv.updateActiveSource(newActive);
+            if (!current.equals(newActive)) {
+                boolean notifyInputChange = (mCallback == null);
+                tv.updateActiveInput(newActive.physicalAddress, notifyInputChange);
             }
             invokeCallback(HdmiControlManager.RESULT_SUCCESS);
         } else {
             // TV is in a mode that should keep its current source/input from
             // being changed for its operation. Reclaim the active source
             // or switch the port back to the one used for the current mode.
-            if (currentActive == getSourceAddress()) {
-                HdmiCecMessage activeSource =
-                        HdmiCecMessageBuilder.buildActiveSource(currentActive, currentPath);
-                mService.sendCecCommand(activeSource);
-                tv.updateActiveSource(currentActive, currentPath);
+            if (current.logicalAddress == getSourceAddress()) {
+                HdmiCecMessage activeSourceCommand = HdmiCecMessageBuilder.buildActiveSource(
+                        current.logicalAddress, current.physicalAddress);
+                mService.sendCecCommand(activeSourceCommand);
+                tv.updateActiveSource(current);
                 invokeCallback(HdmiControlManager.RESULT_SUCCESS);
             } else {
                 HdmiCecMessage routingChange = HdmiCecMessageBuilder.buildRoutingChange(
-                        getSourceAddress(), activePath, currentPath);
+                        getSourceAddress(), newActive.physicalAddress, current.physicalAddress);
                 mService.sendCecCommand(routingChange);
-                tv.addAndStartAction(new RoutingControlAction(tv, currentPath, true, mCallback));
+                tv.addAndStartAction(
+                        new RoutingControlAction(tv, current.physicalAddress, true, mCallback));
             }
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index a75b485..86e14e1 100644
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -69,6 +69,7 @@
         private final int mLogicalAddress;
 
         private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
+        private int mPortId = Constants.INVALID_PORT_ID;
         private int mVendorId = Constants.UNKNOWN_VENDOR_ID;
         private String mDisplayName = "";
         private int mDeviceType = HdmiCecDeviceInfo.DEVICE_INACTIVE;
@@ -78,8 +79,8 @@
         }
 
         private HdmiCecDeviceInfo toHdmiCecDeviceInfo() {
-            return new HdmiCecDeviceInfo(mLogicalAddress, mPhysicalAddress, mDeviceType, mVendorId,
-                    mDisplayName);
+            return new HdmiCecDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType,
+                    mVendorId, mDisplayName);
         }
     }
 
@@ -252,12 +253,17 @@
 
         byte params[] = cmd.getParams();
         current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
+        current.mPortId = getPortId(current.mPhysicalAddress);
         current.mDeviceType = params[2] & 0xFF;
 
         increaseProcessedDeviceCount();
         checkAndProceedStage();
     }
 
+    private int getPortId(int physicalAddress) {
+        return tv().getPortId(physicalAddress);
+    }
+
     private void handleSetOsdName(HdmiCecMessage cmd) {
         Preconditions.checkState(mProcessedDeviceCount < mDevices.size());
 
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index d4fffcf..018b34d 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -130,10 +131,10 @@
                 return false;
             case STATE_WAIT_FOR_ACTIVE_SOURCE:
                 if (opcode == Constants.MESSAGE_ACTIVE_SOURCE) {
-                    int activePath = HdmiUtils.twoBytesToInt(params);
+                    int physicalAddress = HdmiUtils.twoBytesToInt(params);
                     ActiveSourceHandler
                             .create((HdmiCecLocalDeviceTv) localDevice(), mCallback)
-                            .process(cmd.getSource(), activePath);
+                            .process(ActiveSource.of(cmd.getSource(), physicalAddress));
                     finish();
                     return true;
                 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index f1e7ff2..40eb3e44 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -49,9 +49,41 @@
     protected int mPreferredAddress;
     protected HdmiCecDeviceInfo mDeviceInfo;
 
+    static class ActiveSource {
+        int logicalAddress;
+        int physicalAddress;
+
+        public ActiveSource(int logical, int physical) {
+            logicalAddress = logical;
+            physicalAddress = physical;
+        }
+        public static ActiveSource of(int logical, int physical) {
+            return new ActiveSource(logical, physical);
+        }
+        public boolean isValid() {
+            return HdmiUtils.isValidAddress(logicalAddress);
+        }
+        public boolean equals(int logical, int physical) {
+            return logicalAddress == logical && physicalAddress == physical;
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ActiveSource) {
+                ActiveSource that = (ActiveSource) obj;
+                return that.logicalAddress == logicalAddress &&
+                       that.physicalAddress == physicalAddress;
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return logicalAddress * 29 + physicalAddress;
+        }
+    }
     // Logical address of the active source.
     @GuardedBy("mLock")
-    private int mActiveSource;
+    protected final ActiveSource mActiveSource =
+            new ActiveSource(-1, Constants.INVALID_PHYSICAL_ADDRESS);
 
     // Active routing path. Physical address of the active source but not all the time, such as
     // when the new active source does not claim itself to be one. Note that we don't keep
@@ -200,6 +232,8 @@
                 return handleVendorCommandWithId(message);
             case Constants.MESSAGE_SET_OSD_NAME:
                 return handleSetOsdName(message);
+            case Constants.MESSAGE_RECORD_TV_SCREEN:
+                return handleRecordTvScreen(message);
             default:
                 return false;
         }
@@ -403,6 +437,13 @@
         return true;
     }
 
+    protected boolean handleRecordTvScreen(HdmiCecMessage message) {
+        // The default behavior of <Record TV Screen> is replying <Feature Abort> with "Refused".
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
+                message.getSource(), message.getOpcode(), Constants.ABORT_REFUSED));
+        return true;
+    }
+
     @ServiceThreadOnly
     final void handleAddressAllocated(int logicalAddress, boolean fromBootup) {
         assertRunOnServiceThread();
@@ -540,15 +581,24 @@
         return mService.isConnectedToArcPort(path);
     }
 
-    int getActiveSource() {
+    ActiveSource getActiveSource() {
         synchronized (mLock) {
             return mActiveSource;
         }
     }
 
-    void setActiveSource(int source) {
+    void setActiveSource(ActiveSource newActive) {
+        setActiveSource(newActive.logicalAddress, newActive.physicalAddress);
+    }
+
+    void setActiveSource(HdmiCecDeviceInfo info) {
+        setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
+    }
+
+    void setActiveSource(int logicalAddress, int physicalAddress) {
         synchronized (mLock) {
-            mActiveSource = source;
+            mActiveSource.logicalAddress = logicalAddress;
+            mActiveSource.physicalAddress = physicalAddress;
         }
     }
 
@@ -587,13 +637,6 @@
         }
     }
 
-    void updateActiveDevice(int logicalAddress, int physicalAddress) {
-        synchronized (mLock) {
-            mActiveSource = logicalAddress;
-            mActiveRoutingPath = physicalAddress;
-        }
-    }
-
     @ServiceThreadOnly
     HdmiCecMessageCache getCecMessageCache() {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index e985e35..f93d20f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -16,9 +16,18 @@
 
 package com.android.server.hdmi;
 
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CEC_DISABLED;
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION;
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN;
+import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_CEC_DISABLED;
+import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION;
+import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE;
+
 import android.content.Intent;
 import android.hardware.hdmi.HdmiCecDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiRecordSources;
+import android.hardware.hdmi.HdmiTimerRecordSources;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -35,6 +44,7 @@
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -45,7 +55,7 @@
 final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
     private static final String TAG = "HdmiCecLocalDeviceTv";
 
-    // Whether ARC is available or not. "true" means that ARC is estabilished between TV and
+    // Whether ARC is available or not. "true" means that ARC is established between TV and
     // AVR as audio receiver.
     @ServiceThreadOnly
     private boolean mArcEstablished = false;
@@ -137,12 +147,15 @@
         if (targetAddress == Constants.ADDR_INTERNAL) {
             handleSelectInternalSource();
             // Switching to internal source is always successful even when CEC control is disabled.
-            setActiveSource(targetAddress);
+            setActiveSource(targetAddress, mService.getPhysicalAddress());
             invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
             return;
         }
         if (!mService.isControlEnabled()) {
-            setActiveSource(targetAddress);
+            HdmiCecDeviceInfo info = getDeviceInfo(targetAddress);
+            if (info != null) {
+                setActiveSource(info);
+            }
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
         }
@@ -159,7 +172,7 @@
     private void handleSelectInternalSource() {
         assertRunOnServiceThread();
         // Seq #18
-        if (mService.isControlEnabled() && getActiveSource() != mAddress) {
+        if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) {
             updateActiveSource(mAddress, mService.getPhysicalAddress());
             // TODO: Check if this comes from <Text/Image View On> - if true, do nothing.
             HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
@@ -169,16 +182,22 @@
     }
 
     @ServiceThreadOnly
-    void updateActiveSource(int activeSource, int activePath) {
+    void updateActiveSource(int logicalAddress, int physicalAddress) {
+        assertRunOnServiceThread();
+        updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress));
+    }
+
+    @ServiceThreadOnly
+    void updateActiveSource(ActiveSource newActive) {
         assertRunOnServiceThread();
         // Seq #14
-        if (activeSource == getActiveSource() && activePath == getActivePath()) {
+        if (mActiveSource.equals(newActive)) {
             return;
         }
-        setActiveSource(activeSource);
-        setActivePath(activePath);
-        if (getDeviceInfo(activeSource) != null && activeSource != mAddress) {
-            if (mService.pathToPortId(activePath) == getActivePortId()) {
+        setActiveSource(newActive);
+        int logicalAddress = newActive.logicalAddress;
+        if (getDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) {
+            if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) {
                 setPrevPortId(getActivePortId());
             }
             // TODO: Show the OSD banner related to the new active source device.
@@ -188,6 +207,10 @@
         }
     }
 
+    int getPortId(int physicalAddress) {
+        return mService.pathToPortId(physicalAddress);
+    }
+
     /**
      * Returns the previous port id kept to handle input switching on <Inactive Source>.
      */
@@ -208,16 +231,26 @@
     }
 
     @ServiceThreadOnly
-    void updateActivePortId(int portId) {
+    void updateActiveInput(int path, boolean notifyInputChange) {
         assertRunOnServiceThread();
         // Seq #15
+        int portId = mService.pathToPortId(path);
         if (portId == getActivePortId()) {
             return;
         }
+        setActivePath(path);
         setPrevPortId(portId);
-        // TODO: Actually switch the physical port here. Handle PAP/PIP as well.
-        //       Show OSD port change banner
-        mService.invokeInputChangeListener(getActiveSource());
+        // TODO: Handle PAP/PIP case.
+        // Show OSD port change banner
+        if (notifyInputChange) {
+            ActiveSource activeSource = getActiveSource();
+            HdmiCecDeviceInfo info = getDeviceInfo(activeSource.logicalAddress);
+            if (info == null) {
+                info = new HdmiCecDeviceInfo(Constants.ADDR_INVALID, path, portId,
+                        HdmiCecDeviceInfo.DEVICE_RESERVED, 0, null);
+            }
+            mService.invokeInputChangeListener(info);
+        }
     }
 
     @ServiceThreadOnly
@@ -228,26 +261,25 @@
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
         }
+        if (portId == getActivePortId()) {
+            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+            return;
+        }
+        setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
         if (!mService.isControlEnabled()) {
             setActivePortId(portId);
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
         }
-        if (portId == getActivePortId()) {
-            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
-            return;
-        }
-        setActivePortId(portId);
         // TODO: Return immediately if the operation is triggered by <Text/Image View On>
-        //       and this is the first notification about the active input after power-on
-        //       (switch to HDMI didn't happen so far but is expected to happen soon).
-        removeAction(RoutingControlAction.class);
-
-        int oldPath = mService.portIdToPath(mService.portIdToPath(getActivePortId()));
+        // and this is the first notification about the active input after power-on
+        // (switch to HDMI didn't happen so far but is expected to happen soon).
+        int oldPath = mService.portIdToPath(getActivePortId());
         int newPath = mService.portIdToPath(portId);
         HdmiCecMessage routingChange =
                 HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
         mService.sendCecCommand(routingChange);
+        removeAction(RoutingControlAction.class);
         addAndStartAction(new RoutingControlAction(this, newPath, false, callback));
     }
 
@@ -270,7 +302,8 @@
             action.get(0).processKeyEvent(keyCode, isPressed);
         } else {
             if (isPressed) {
-                addAndStartAction(new SendKeyAction(this, getActiveSource(), keyCode));
+                int logicalAddress = getActiveSource().logicalAddress;
+                addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
             } else {
                 Slog.w(TAG, "Discard key release event");
             }
@@ -292,12 +325,13 @@
     @ServiceThreadOnly
     protected boolean handleActiveSource(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        int address = message.getSource();
-        int path = HdmiUtils.twoBytesToInt(message.getParams());
-        if (getDeviceInfo(address) == null) {
-            handleNewDeviceAtTheTailOfActivePath(path);
+        int logicalAddress = message.getSource();
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        if (getDeviceInfo(logicalAddress) == null) {
+            handleNewDeviceAtTheTailOfActivePath(physicalAddress);
         } else {
-            ActiveSourceHandler.create(this, null).process(address, path);
+            ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
+            ActiveSourceHandler.create(this, null).process(activeSource);
         }
         return true;
     }
@@ -309,7 +343,7 @@
         // Seq #10
 
         // Ignore <Inactive Source> from non-active source device.
-        if (getActiveSource() != message.getSource()) {
+        if (getActiveSource().logicalAddress != message.getSource()) {
             return true;
         }
         if (isProhibitMode()) {
@@ -328,7 +362,6 @@
             }
             // TODO: Switch the TV freeze mode off
 
-            setActivePortId(portId);
             doManualPortSwitching(portId, null);
             setPrevPortId(Constants.INVALID_PORT_ID);
         }
@@ -340,7 +373,7 @@
     protected boolean handleRequestActiveSource(HdmiCecMessage message) {
         assertRunOnServiceThread();
         // Seq #19
-        if (mAddress == getActiveSource()) {
+        if (mAddress == getActiveSource().logicalAddress) {
             mService.sendCecCommand(
                     HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath()));
         }
@@ -378,11 +411,11 @@
         if (!isInDeviceList(path, address)) {
             handleNewDeviceAtTheTailOfActivePath(path);
         }
-        startNewDeviceAction(address, path);
+        startNewDeviceAction(ActiveSource.of(address, path));
         return true;
     }
 
-    void startNewDeviceAction(int address, int path) {
+    void startNewDeviceAction(ActiveSource activeSource) {
         for (NewDeviceAction action : getActions(NewDeviceAction.class)) {
             // If there is new device action which has the same logical address and path
             // ignore new request.
@@ -392,12 +425,13 @@
             // in. However, TV can detect a new device from HotPlugDetectionAction,
             // which sends <Give Physical Address> to the source for newly detected
             // device.
-            if (action.isActionOf(address, path)) {
+            if (action.isActionOf(activeSource)) {
                 return;
             }
         }
 
-        addAndStartAction(new NewDeviceAction(this, address, path));
+        addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
+                activeSource.physicalAddress));
     }
 
     private void handleNewDeviceAtTheTailOfActivePath(int path) {
@@ -510,8 +544,8 @@
         }
 
         addCecDevice(new HdmiCecDeviceInfo(deviceInfo.getLogicalAddress(),
-                deviceInfo.getPhysicalAddress(), deviceInfo.getDeviceType(),
-                deviceInfo.getVendorId(), osdName));
+                deviceInfo.getPhysicalAddress(), deviceInfo.getPortId(),
+                deviceInfo.getDeviceType(), deviceInfo.getVendorId(), osdName));
         return true;
     }
 
@@ -808,6 +842,35 @@
         return true;
     }
 
+    // Seq #53
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRecordTvScreen(HdmiCecMessage message) {
+        List<OneTouchRecordAction> actions = getActions(OneTouchRecordAction.class);
+        if (!actions.isEmpty()) {
+            // Assumes only one OneTouchRecordAction.
+            OneTouchRecordAction action = actions.get(0);
+            if (action.getRecorderAddress() != message.getSource()) {
+                announceOneTouchRecordResult(
+                        HdmiControlManager.ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS);
+            }
+            return super.handleRecordTvScreen(message);
+        }
+
+        int recorderAddress = message.getSource();
+        byte[] recordSource = mService.invokeRecordRequestListener(recorderAddress);
+        startOneTouchRecord(recorderAddress, recordSource);
+        return true;
+    }
+
+    void announceOneTouchRecordResult(int result) {
+        mService.invokeOneTouchRecordResult(result);
+    }
+
+    void announceTimerRecordingResult(int result) {
+        mService.invokeTimerRecordingResult(result);
+    }
+
     private boolean isMessageForSystemAudio(HdmiCecMessage message) {
         if (message.getSource() != Constants.ADDR_AUDIO_SYSTEM
                 || message.getDestination() != Constants.ADDR_TV
@@ -1129,6 +1192,8 @@
         //     LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery().
         removeAction(DeviceDiscoveryAction.class);
         removeAction(HotplugDetectionAction.class);
+        // Remove one touch record action.
+        removeAction(OneTouchRecordAction.class);
 
         disableSystemAudioIfExist();
         disableArcIfExist();
@@ -1210,4 +1275,104 @@
         mService.getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
                 HdmiControlService.PERMISSION);
     }
+
+    // Seq #54 and #55
+    @ServiceThreadOnly
+    void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
+        assertRunOnServiceThread();
+        if (!mService.isControlEnabled()) {
+            Slog.w(TAG, "Can not start one touch record. CEC control is disabled.");
+            announceOneTouchRecordResult(ONE_TOUCH_RECORD_CEC_DISABLED);
+            return;
+        }
+
+        if (!checkRecorder(recorderAddress)) {
+            Slog.w(TAG, "Invalid recorder address:" + recorderAddress);
+            announceOneTouchRecordResult(ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION);
+            return;
+        }
+
+        if (!checkRecordSource(recordSource)) {
+            Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource));
+            announceOneTouchRecordResult(ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN);
+            return;
+        }
+
+        addAndStartAction(new OneTouchRecordAction(this, recorderAddress, recordSource));
+        Slog.i(TAG, "Start new [One Touch Record]-Target:" + recorderAddress + ", recordSource:"
+                + Arrays.toString(recordSource));
+    }
+
+    @ServiceThreadOnly
+    void stopOneTouchRecord(int recorderAddress) {
+        assertRunOnServiceThread();
+        if (!mService.isControlEnabled()) {
+            Slog.w(TAG, "Can not stop one touch record. CEC control is disabled.");
+            announceOneTouchRecordResult(ONE_TOUCH_RECORD_CEC_DISABLED);
+            return;
+        }
+
+        if (!checkRecorder(recorderAddress)) {
+            Slog.w(TAG, "Invalid recorder address:" + recorderAddress);
+            announceOneTouchRecordResult(ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION);
+            return;
+        }
+
+        // Remove one touch record action so that other one touch record can be started.
+        removeAction(OneTouchRecordAction.class);
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildRecordOff(mAddress, recorderAddress));
+        Slog.i(TAG, "Stop [One Touch Record]-Target:" + recorderAddress);
+    }
+
+    private boolean checkRecorder(int recorderAddress) {
+        HdmiCecDeviceInfo device = getDeviceInfo(recorderAddress);
+        return (device != null)
+                && (HdmiUtils.getTypeFromAddress(recorderAddress)
+                        == HdmiCecDeviceInfo.DEVICE_RECORDER);
+    }
+
+    private boolean checkRecordSource(byte[] recordSource) {
+        return (recordSource != null) && HdmiRecordSources.checkRecordSource(recordSource);
+    }
+
+    @ServiceThreadOnly
+    void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
+        assertRunOnServiceThread();
+        if (!mService.isControlEnabled()) {
+            Slog.w(TAG, "Can not start one touch record. CEC control is disabled.");
+            announceTimerRecordingResult(TIME_RECORDING_RESULT_EXTRA_CEC_DISABLED);
+            return;
+        }
+
+        if (!checkRecorder(recorderAddress)) {
+            Slog.w(TAG, "Invalid recorder address:" + recorderAddress);
+            announceTimerRecordingResult(
+                    TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION);
+            return;
+        }
+
+        if (!checkTimerRecordingSource(sourceType, recordSource)) {
+            Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource));
+            announceTimerRecordingResult(
+                    TIME_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE);
+            return;
+        }
+
+        addAndStartAction(
+                new TimerRecordingAction(this, recorderAddress, sourceType, recordSource));
+        Slog.i(TAG, "Start [Timer Recording]-Target:" + recorderAddress + ", SourceType:"
+                + sourceType + ", RecordSource:" + Arrays.toString(recordSource));
+    }
+
+    private boolean checkTimerRecordingSource(int sourceType, byte[] recordSource) {
+        return (recordSource != null)
+                && HdmiTimerRecordSources.checkTimerRecordSource(sourceType, recordSource);
+    }
+
+    @ServiceThreadOnly
+    void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
+        assertRunOnServiceThread();
+
+        // TODO: implement this.
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 0b6c3c5..0855bfa 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -455,6 +455,101 @@
         return buildCommand(src, dest, Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, params);
     }
 
+    /**
+     * Build &lt;Record On&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param params parameter of command
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildRecordOn(int src, int dest, byte[] params) {
+        return buildCommand(src, dest, Constants.MESSAGE_RECORD_ON, params);
+    }
+
+    /**
+     * Build &lt;Record Off&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildRecordOff(int src, int dest) {
+        return buildCommand(src, dest, Constants.MESSAGE_RECORD_OFF);
+    }
+
+    /**
+     * Build &lt;Set Digital Timer&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param params byte array of timing information and digital service information to be recorded
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildSetDigitalTimer(int src, int dest, byte[] params) {
+        return buildCommand(src, dest, Constants.MESSAGE_SET_DIGITAL_TIMER, params);
+    }
+
+    /**
+     * Build &lt;Set Analogue Timer&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param params byte array of timing information and analog service information to be recorded
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildSetAnalogueTimer(int src, int dest, byte[] params) {
+        return buildCommand(src, dest, Constants.MESSAGE_SET_ANALOG_TIMER, params);
+    }
+
+    /**
+     * Build &lt;Set External Timer&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param params byte array of timing information and external source information to be recorded
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildSetExternalTimer(int src, int dest, byte[] params) {
+        return buildCommand(src, dest, Constants.MESSAGE_SET_EXTERNAL_TIMER, params);
+    }
+
+    /**
+     * Build &lt;Clear Digital Timer&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param params byte array of timing information and digital service information to be cleared
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildClearDigitalTimer(int src, int dest, byte[] params) {
+        return buildCommand(src, dest, Constants.MESSAGE_CLEAR_DIGITAL_TIMER, params);
+    }
+
+    /**
+     * Build &lt;Clear Analog Timer&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param params byte array of timing information and analog service information to be cleared
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildClearAnalogueTimer(int src, int dest, byte[] params) {
+        return buildCommand(src, dest, Constants.MESSAGE_CLEAR_ANALOG_TIMER, params);
+    }
+
+    /**
+     * Build &lt;Clear Digital Timer&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param params byte array of timing information and external source information to be cleared
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildClearExternalTimer(int src, int dest, byte[] params) {
+        return buildCommand(src, dest, Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, params);
+    }
+
     /***** Please ADD new buildXXX() methods above. ******/
 
     /**
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index c9330c5..d491ac2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -243,12 +243,17 @@
     }
 
     private boolean isValidPhysicalAddress(byte[] params, int offset) {
+        // TODO: Add more logic like validating 1.0.1.0.
+
+        if (!mService.isTvDevice()) {
+            // If the device is not TV, we can't convert path to port-id, so stop here.
+            return true;
+        }
         int path = HdmiUtils.twoBytesToInt(params, offset);
         int portId = mService.pathToPortId(path);
         if (portId == Constants.INVALID_PORT_ID) {
             return false;
         }
-        // TODO: Add more logic like validating 1.0.1.0.
         return true;
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 95cd7ef..37c297b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -32,7 +32,7 @@
 import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
 import android.hardware.hdmi.IHdmiInputChangeListener;
-import android.hardware.hdmi.IHdmiRecordRequestListener;
+import android.hardware.hdmi.IHdmiRecordListener;
 import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.hardware.hdmi.IHdmiVendorCommandListener;
 import android.media.AudioManager;
@@ -45,6 +45,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.Settings.Global;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -55,6 +56,8 @@
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
 import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
 
+import libcore.util.EmptyArray;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -157,6 +160,12 @@
     @GuardedBy("mLock")
     private InputChangeListenerRecord mInputChangeListenerRecord;
 
+    @GuardedBy("mLock")
+    private IHdmiRecordListener mRecordListener;
+
+    @GuardedBy("mLock")
+    private HdmiRecordListenerRecord mRecordListenerRecord;
+
     // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol
     // handling will be disabled and no request will be handled.
     @GuardedBy("mLock")
@@ -189,6 +198,12 @@
     // from being modified.
     private List<HdmiPortInfo> mPortInfo;
 
+    // Map from path(physical address) to port ID.
+    private SparseIntArray mPortIdMap = new SparseIntArray();
+
+    // Map from port ID to HdmiPortInfo.
+    private SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>();
+
     private HdmiCecMessageValidator mMessageValidator;
 
     private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver();
@@ -230,7 +245,7 @@
         if (mMhlController == null) {
             Slog.i(TAG, "Device does not support MHL-control.");
         }
-        mPortInfo = initPortInfo();
+        initPortInfo();
         mMessageValidator = new HdmiCecMessageValidator(this);
         publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
 
@@ -310,7 +325,7 @@
     // Initialize HDMI port information. Combine the information from CEC and MHL HAL and
     // keep them in one place.
     @ServiceThreadOnly
-    private List<HdmiPortInfo> initPortInfo() {
+    private void initPortInfo() {
         assertRunOnServiceThread();
         HdmiPortInfo[] cecPortInfo = null;
 
@@ -320,7 +335,12 @@
             cecPortInfo = mCecController.getPortInfos();
         }
         if (cecPortInfo == null) {
-            return Collections.emptyList();
+            return;
+        }
+
+        for (HdmiPortInfo info : cecPortInfo) {
+            mPortIdMap.put(info.getAddress(), info.getId());
+            mPortInfoMap.put(info.getId(), info);
         }
 
         HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0];
@@ -329,27 +349,24 @@
             // mhlPortInfo = mMhlController.getPortInfos();
         }
 
-        // Use the id (port number) to find the matched info between CEC and MHL to combine them
-        // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found.
-        ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length);
-        for (int i = 0; i < cecPortInfo.length; ++i) {
-            HdmiPortInfo cec = cecPortInfo[i];
-            int id = cec.getId();
-            boolean mhlInfoFound = false;
-            for (HdmiPortInfo mhl : mhlPortInfo) {
-                if (id == mhl.getId()) {
-                    result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(),
-                            cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported()));
-                    mhlInfoFound = true;
-                    break;
-                }
-            }
-            if (!mhlInfoFound) {
-                result.add(cec);
+        ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length);
+        for (HdmiPortInfo info : mhlPortInfo) {
+            if (info.isMhlSupported()) {
+                mhlSupportedPorts.add(info.getId());
             }
         }
 
-        return Collections.unmodifiableList(result);
+        // Build HDMI port info list with CEC port info plus MHL supported flag.
+        ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length);
+        for (HdmiPortInfo info : cecPortInfo) {
+            if (mhlSupportedPorts.contains(info.getId())) {
+                result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(),
+                        info.isCecSupported(), true, info.isArcSupported()));
+            } else {
+                result.add(info);
+            }
+        }
+        mPortInfo = Collections.unmodifiableList(result);
     }
 
     /**
@@ -358,22 +375,19 @@
      * @param portId HDMI port id
      * @return {@link HdmiPortInfo} for the given port
      */
+    @ServiceThreadOnly
     HdmiPortInfo getPortInfo(int portId) {
-        // mPortInfo is an unmodifiable list and the only reference to its inner list.
-        // No lock is necessary.
-        for (HdmiPortInfo info : mPortInfo) {
-            if (portId == info.getId()) {
-                return info;
-            }
-        }
-        return null;
+        assertRunOnServiceThread();
+        return mPortInfoMap.get(portId, null);
     }
 
     /**
      * Returns the routing path (physical address) of the HDMI port for the given
      * port id.
      */
+    @ServiceThreadOnly
     int portIdToPath(int portId) {
+        assertRunOnServiceThread();
         HdmiPortInfo portInfo = getPortInfo(portId);
         if (portInfo == null) {
             Slog.e(TAG, "Cannot find the port info: " + portId);
@@ -388,23 +402,17 @@
      * the port id to be returned is the ID associated with the port address
      * 0x1000 (1.0.0.0) which is the topmost path of the given routing path.
      */
+    @ServiceThreadOnly
     int pathToPortId(int path) {
+        assertRunOnServiceThread();
         int portAddress = path & Constants.ROUTING_PATH_TOP_MASK;
-        for (HdmiPortInfo info : mPortInfo) {
-            if (portAddress == info.getAddress()) {
-                return info.getId();
-            }
-        }
-        return Constants.INVALID_PORT_ID;
+        return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID);
     }
 
+    @ServiceThreadOnly
     boolean isValidPortId(int portId) {
-        for (HdmiPortInfo info : mPortInfo) {
-            if (portId == info.getId()) {
-                return true;
-            }
-        }
-        return false;
+        assertRunOnServiceThread();
+        return getPortInfo(portId) != null;
     }
 
     /**
@@ -460,12 +468,12 @@
     /**
      * Whether a device of the specified physical address is connected to ARC enabled port.
      */
+    @ServiceThreadOnly
     boolean isConnectedToArcPort(int physicalAddress) {
-        for (HdmiPortInfo portInfo : mPortInfo) {
-            if (hasSameTopPort(portInfo.getAddress(), physicalAddress)
-                    && portInfo.isArcSupported()) {
-                return true;
-            }
+        assertRunOnServiceThread();
+        int portId = mPortIdMap.get(physicalAddress);
+        if (portId != Constants.INVALID_PORT_ID) {
+            return mPortInfoMap.get(portId).isArcSupported();
         }
         return false;
     }
@@ -614,7 +622,8 @@
         // TODO: find better name instead of model name.
         String displayName = Build.MODEL;
         return new HdmiCecDeviceInfo(logicalAddress,
-                getPhysicalAddress(), deviceType, getVendorId(), displayName);
+                getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType,
+                getVendorId(), displayName);
     }
 
     // Record class that monitors the event of the caller of being killed. Used to clean up
@@ -684,6 +693,15 @@
         }
     }
 
+    private class HdmiRecordListenerRecord implements IBinder.DeathRecipient {
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mRecordListener = null;
+            }
+        }
+    }
+
     private void enforceAccessPermission() {
         getContext().enforceCallingOrSelfPermission(PERMISSION, TAG);
     }
@@ -706,6 +724,10 @@
             runOnServiceThread(new Runnable() {
                 @Override
                 public void run() {
+                    if (callback == null) {
+                        Slog.e(TAG, "Callback cannot be null");
+                        return;
+                    }
                     HdmiCecLocalDeviceTv tv = tv();
                     if (tv == null) {
                         Slog.w(TAG, "Local tv device not available");
@@ -723,6 +745,10 @@
             runOnServiceThread(new Runnable() {
                 @Override
                 public void run() {
+                    if (callback == null) {
+                        Slog.e(TAG, "Callback cannot be null");
+                        return;
+                    }
                     HdmiCecLocalDeviceTv tv = tv();
                     if (tv == null) {
                         Slog.w(TAG, "Local tv device not available");
@@ -963,10 +989,6 @@
             }
         }
 
-        private boolean isTvDevice() {
-            return tv() != null;
-        }
-
         @Override
         public void setProhibitMode(final boolean enabled) {
             enforceAccessPermission();
@@ -1010,21 +1032,69 @@
                     }
                 }
             });
-         }
-
-        @Override
-        public void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener) {
-            // TODO: implement this.
         }
 
         @Override
-        public void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
-            // TODO: implement this.
+        public void setHdmiRecordListener(IHdmiRecordListener listener) {
+            HdmiControlService.this.setHdmiRecordListener(listener);
         }
 
         @Override
-        public void startTimerRecording(int recorderAddress, byte[] recordSource) {
-            // TODO: implement this.
+        public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) {
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (!isTvDevice()) {
+                        Slog.w(TAG, "No TV is available.");
+                        return;
+                    }
+                    tv().startOneTouchRecord(recorderAddress, recordSource);
+                }
+            });
+        }
+
+        @Override
+        public void stopOneTouchRecord(final int recorderAddress) {
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (!isTvDevice()) {
+                        Slog.w(TAG, "No TV is available.");
+                        return;
+                    }
+                    tv().stopOneTouchRecord(recorderAddress);
+                }
+            });
+        }
+
+        @Override
+        public void startTimerRecording(final int recorderAddress, final int sourceType,
+                final byte[] recordSource) {
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (!isTvDevice()) {
+                        Slog.w(TAG, "No TV is available.");
+                        return;
+                    }
+                    tv().startTimerRecording(recorderAddress, sourceType, recordSource);
+                }
+            });
+        }
+
+        @Override
+        public void clearTimerRecording(final int recorderAddress, final int sourceType,
+                final byte[] recordSource) {
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (!isTvDevice()) {
+                        Slog.w(TAG, "No TV is available.");
+                        return;
+                    }
+                    tv().clearTimerRecording(recorderAddress, sourceType, recordSource);
+                }
+            });
         }
     }
 
@@ -1156,12 +1226,11 @@
         }
     }
 
-    void invokeInputChangeListener(int activeAddress) {
+    void invokeInputChangeListener(HdmiCecDeviceInfo info) {
         synchronized (mLock) {
             if (mInputChangeListener != null) {
-                HdmiCecDeviceInfo activeSource = getDeviceInfo(activeAddress);
                 try {
-                    mInputChangeListener.onChanged(activeSource);
+                    mInputChangeListener.onChanged(info);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e);
                 }
@@ -1169,6 +1238,55 @@
         }
     }
 
+    private void setHdmiRecordListener(IHdmiRecordListener listener) {
+        synchronized (mLock) {
+            mRecordListenerRecord = new HdmiRecordListenerRecord();
+            try {
+                listener.asBinder().linkToDeath(mRecordListenerRecord, 0);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Listener already died.", e);
+            }
+            mRecordListener = listener;
+        }
+    }
+
+    byte[] invokeRecordRequestListener(int recorderAddress) {
+        synchronized (mLock) {
+            if (mRecordListener != null) {
+                try {
+                    return mRecordListener.getOneTouchRecordSource(recorderAddress);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to start record.", e);
+                }
+            }
+            return EmptyArray.BYTE;
+        }
+    }
+
+    void invokeOneTouchRecordResult(int result) {
+        synchronized (mLock) {
+            if (mRecordListener != null) {
+                try {
+                    mRecordListener.onOneTouchRecordResult(result);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e);
+                }
+            }
+        }
+    }
+
+    void invokeTimerRecordingResult(int result) {
+        synchronized (mLock) {
+            if (mRecordListener != null) {
+                try {
+                    mRecordListener.onTimerRecordingResult(result);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e);
+                }
+            }
+        }
+    }
+
     private void invokeCallback(IHdmiControlCallback callback, int result) {
         try {
             callback.onComplete(result);
@@ -1213,6 +1331,10 @@
         return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_TV);
     }
 
+    boolean isTvDevice() {
+        return tv() != null;
+    }
+
     private HdmiCecLocalDevicePlayback playback() {
         return (HdmiCecLocalDevicePlayback)
                 mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_PLAYBACK);
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 7d7a95b..907015b 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -18,6 +18,7 @@
 import android.hardware.hdmi.HdmiCecDeviceInfo;
 import android.util.Slog;
 
+import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 import java.io.UnsupportedEncodingException;
 
 /**
@@ -153,6 +154,7 @@
         }
         tv().addCecDevice(new HdmiCecDeviceInfo(
                 mDeviceLogicalAddress, mDevicePhysicalAddress,
+                tv().getPortId(mDevicePhysicalAddress),
                 HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress),
                 mVendorId, mDisplayName));
 
@@ -189,7 +191,8 @@
         }
     }
 
-    boolean isActionOf(int address, int path) {
-        return (mDeviceLogicalAddress == address) && (mDevicePhysicalAddress == path);
+    boolean isActionOf(ActiveSource activeSource) {
+        return (mDeviceLogicalAddress == activeSource.logicalAddress)
+                && (mDevicePhysicalAddress == activeSource.physicalAddress);
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index 51aa984..befc640 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -16,51 +16,115 @@
 
 package com.android.server.hdmi;
 
-import static com.android.server.hdmi.Constants.RECORDING_TYPE_ANALOGUE_RF;
-import static com.android.server.hdmi.Constants.RECORDING_TYPE_DIGITAL_RF;
-import static com.android.server.hdmi.Constants.RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS;
-import static com.android.server.hdmi.Constants.RECORDING_TYPE_OWN_SOURCE;
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION;
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE;
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE;
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE;
+import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT;
+
+import android.util.Slog;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
- * Feature action that performs one touch record. This class only provides a skeleton of one touch
- * play and has no detail implementation.
+ * Feature action that performs one touch record.
  */
 public class OneTouchRecordAction extends FeatureAction {
-    private final int mRecorderAddress;
-    private final int mRecordingType;
+    private static final String TAG = "OneTouchRecordAction";
 
-    OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, int recordingType) {
+    // Timer out for waiting <Record Status> 120s
+    private static final int RECORD_STATUS_TIMEOUT_MS = 120000;
+
+    // State that waits for <Record Status> once sending <Record On>
+    private static final int STATE_WAITING_FOR_RECORD_STATUS = 1;
+    // State that describes recording in progress.
+    private static final int STATE_RECORDING_IN_PROGRESS = 2;
+
+    private final int mRecorderAddress;
+    private final byte[] mRecordSource;
+
+    OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, byte[] recordSource) {
         super(source);
         mRecorderAddress = recorderAddress;
-        mRecordingType = recordingType;
+        mRecordSource = recordSource;
     }
 
     @Override
     boolean start() {
-        return false;
+        sendRecordOn();
+        return true;
     }
 
-    private void sendRecordOn(int recordingType) {
-        switch (recordingType) {
-            case RECORDING_TYPE_DIGITAL_RF:
-                break;
-            case RECORDING_TYPE_ANALOGUE_RF:
-                break;
-            case RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS:
-                break;
-            case RECORDING_TYPE_OWN_SOURCE:
-                break;
-            // TODO: implement this.
-        }
+    private void sendRecordOn() {
+        sendCommand(HdmiCecMessageBuilder.buildRecordOn(getSourceAddress(), mRecorderAddress,
+                mRecordSource),
+                new SendMessageCallback() {
+                @Override
+                    public void onSendCompleted(int error) {
+                        // if failed to send <Record On>, display error message and finish action.
+                        if (error != Constants.SEND_RESULT_SUCCESS) {
+                            tv().announceOneTouchRecordResult(
+                                    ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION);
+                            finish();
+                            return;
+                        }
+
+                        mState = STATE_WAITING_FOR_RECORD_STATUS;
+                        addTimer(mState, RECORD_STATUS_TIMEOUT_MS);
+                    }
+                });
     }
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
+        if (mState != STATE_WAITING_FOR_RECORD_STATUS) {
+            return false;
+        }
+
+        switch (cmd.getOpcode()) {
+            case Constants.MESSAGE_RECORD_STATUS:
+                return handleRecordStatus(cmd);
+
+        }
         return false;
     }
 
+    private boolean handleRecordStatus(HdmiCecMessage cmd) {
+        // Only handle message coming from original recorder.
+        if (cmd.getSource() != mRecorderAddress) {
+            return false;
+        }
+
+        int recordStatus = cmd.getParams()[0];
+        tv().announceOneTouchRecordResult(recordStatus);
+        Slog.i(TAG, "Got record status:" + recordStatus + " from " + cmd.getSource());
+
+        // If recording started successfully, change state and keep this action until <Record Off>
+        // received. Otherwise, finish action.
+        switch (recordStatus) {
+            case ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE:
+            case ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE:
+            case ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE:
+            case ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT:
+                mState = STATE_RECORDING_IN_PROGRESS;
+                mActionTimer.clearTimerMessage();
+                break;
+            default:
+                finish();
+                break;
+        }
+        return true;
+    }
+
     @Override
     void handleTimerEvent(int state) {
+        if (mState != state) {
+            Slog.w(TAG, "Timeout in invalid state:[Expected:" + mState + ", Actual:" + state + "]");
+            return;
+        }
+
+        tv().announceOneTouchRecordResult(ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION);
+        finish();
     }
 
     int getRecorderAddress() {
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index 8296f69..f05394f 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -60,6 +60,12 @@
     // true if <Give Power Status> should be sent once the new active routing path is determined.
     private final boolean mQueryDevicePowerStatus;
 
+    // If set to true, call {@link HdmiControlService#invokeInputChangeListener()} when
+    // the routing control/active source change happens. The listener should be called if
+    // the events are triggered by external events such as manual switch port change or incoming
+    // <Inactive Source> command.
+    private final boolean mNotifyInputChange;
+
     @Nullable private final IHdmiControlCallback mCallback;
 
     // The latest routing path. Updated by each <Routing Information> from CEC switches.
@@ -71,6 +77,11 @@
         mCallback = callback;
         mCurrentRoutingPath = path;
         mQueryDevicePowerStatus = queryDevicePowerStatus;
+        // Callback is non-null when routing control action is brought up by binder API. Use
+        // this as an indicator for the input change notification. These API calls will get
+        // the result through this callback, not through notification. Any other events that
+        // trigger the routing control is external, for which notifcation is used.
+        mNotifyInputChange = (callback == null);
     }
 
     @Override
@@ -111,7 +122,7 @@
             if (isPowerOnOrTransient(devicePowerStatus)) {
                 sendSetStreamPath();
             } else {
-                tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
+                tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
             }
         }
         finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
@@ -155,13 +166,13 @@
                         }
                     });
                 } else {
-                    tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
+                    tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
                     finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
                 }
                 return;
             case STATE_WAIT_FOR_REPORT_POWER_STATUS:
                 if (isPowerOnOrTransient(getTvPowerStatus())) {
-                    tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
+                    tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
                     sendSetStreamPath();
                 }
                 finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
@@ -179,7 +190,7 @@
             mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
             addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
         } else {
-            tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
+            tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
             sendSetStreamPath();
             finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
         }
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
new file mode 100644
index 0000000..1dc26f1
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -0,0 +1,169 @@
+/*
+ * 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.hdmi;
+
+import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE;
+import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
+import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
+import static android.hardware.hdmi.HdmiControlManager.TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION;
+
+import android.util.Slog;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+import java.util.Arrays;
+
+/**
+ * Feature action that performs timer recording.
+ */
+public class TimerRecordingAction extends FeatureAction {
+    private static final String TAG = "TimerRecordingAction";
+
+    // Timer out for waiting <Timer Status> 120s.
+    private static final int TIMER_STATUS_TIMEOUT_MS = 120000;
+
+    // State that waits for <Timer Status> once sending <Set XXX Timer>
+    private static final int STATE_WAITING_FOR_TIMER_STATUS = 1;
+
+    private final int mRecorderAddress;
+    private final int mSourceType;
+    private final byte[] mRecordSource;
+
+    TimerRecordingAction(HdmiCecLocalDevice source, int recorderAddress, int sourceType,
+            byte[] recordSource) {
+        super(source);
+        mRecorderAddress = recorderAddress;
+        mSourceType = sourceType;
+        mRecordSource = recordSource;
+    }
+
+    @Override
+    boolean start() {
+        sendTimerMessage();
+        return true;
+    }
+
+    private void sendTimerMessage() {
+        HdmiCecMessage message = null;
+        switch (mSourceType) {
+            case TIMER_RECORDING_TYPE_DIGITAL:
+                message = HdmiCecMessageBuilder.buildSetDigitalTimer(getSourceAddress(),
+                        mRecorderAddress, mRecordSource);
+                break;
+            case TIMER_RECORDING_TYPE_ANALOGUE:
+                message = HdmiCecMessageBuilder.buildSetAnalogueTimer(getSourceAddress(),
+                        mRecorderAddress, mRecordSource);
+                break;
+            case TIMER_RECORDING_TYPE_EXTERNAL:
+                message = HdmiCecMessageBuilder.buildSetExternalTimer(getSourceAddress(),
+                        mRecorderAddress, mRecordSource);
+                break;
+            default:
+                tv().announceTimerRecordingResult(
+                        TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION);
+                finish();
+                return;
+        }
+        sendCommand(message, new SendMessageCallback() {
+            @Override
+            public void onSendCompleted(int error) {
+                if (error != Constants.SEND_RESULT_SUCCESS) {
+                    mState = STATE_WAITING_FOR_TIMER_STATUS;
+                    addTimer(mState, TIMER_STATUS_TIMEOUT_MS);
+                    finish();
+                    return;
+                }
+            }
+        });
+    }
+
+    @Override
+    boolean processCommand(HdmiCecMessage cmd) {
+        if (mState != STATE_WAITING_FOR_TIMER_STATUS) {
+            return false;
+        }
+
+        if (cmd.getSource() != mRecorderAddress) {
+            return false;
+        }
+
+        switch (cmd.getOpcode()) {
+            case Constants.MESSAGE_TIMER_STATUS:
+                return handleTimerStatus(cmd);
+            case Constants.MESSAGE_FEATURE_ABORT:
+                return handleFeatureAbort(cmd);
+        }
+        return false;
+    }
+
+    private boolean handleTimerStatus(HdmiCecMessage cmd) {
+        byte[] timerStatusData = cmd.getParams();
+        // [Timer Status Data] should be one or three bytes.
+        if (timerStatusData.length == 1 || timerStatusData.length == 3) {
+            tv().announceTimerRecordingResult(bytesToInt(timerStatusData));
+            Slog.i(TAG, "Received [Timer Status Data]:" + Arrays.toString(timerStatusData));
+        } else {
+            Slog.w(TAG, "Invalid [Timer Status Data]:" + Arrays.toString(timerStatusData));
+        }
+
+        // Unlike one touch record, finish timer record when <Timer Status> is received.
+        finish();
+        return true;
+    }
+
+    private boolean handleFeatureAbort(HdmiCecMessage cmd) {
+        byte[] params = cmd.getParams();
+        int messageType = params[0];
+        switch (messageType) {
+            case Constants.MESSAGE_SET_DIGITAL_TIMER: // fall through
+            case Constants.MESSAGE_SET_ANALOG_TIMER: // fall through
+            case Constants.MESSAGE_SET_EXTERNAL_TIMER: // fall through
+                break;
+            default:
+                return false;
+        }
+        int reason = params[1];
+        Slog.i(TAG, "[Feature Abort] for " + messageType + " reason:" + reason);
+        tv().announceTimerRecordingResult(TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION);
+        finish();
+        return true;
+    }
+
+    // Convert byte array to int.
+    private static int bytesToInt(byte[] data) {
+        if (data.length > 4) {
+            throw new IllegalArgumentException("Invalid data size:" + Arrays.toString(data));
+        }
+        int result = 0;
+        for (int i = 0; i < data.length; ++i) {
+            int shift = (3 - i) * 8;
+            result |= ((data[i] & 0xFF) << shift);
+        }
+        return result;
+    }
+
+    @Override
+    void handleTimerEvent(int state) {
+        if (mState != state) {
+            Slog.w(TAG, "Timeout in invalid state:[Expected:" + mState + ", Actual:" + state + "]");
+            return;
+        }
+
+        tv().announceTimerRecordingResult(TIME_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION);
+        finish();
+    }
+}
diff --git a/services/core/java/com/android/server/job/JobMapReadFinishedListener.java b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
deleted file mode 100644
index f3e77e6..0000000
--- a/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
+++ /dev/null
@@ -1,34 +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.server.job;
-
-import java.util.List;
-
-import com.android.server.job.controllers.JobStatus;
-
-/**
- * Callback definition for I/O thread to let the JobManagerService know when
- * I/O read has completed. Done this way so we don't stall the main thread on
- * boot.
- */
-public interface JobMapReadFinishedListener {
-
-    /**
-     * Called by the {@link JobStore} at boot, when the disk read is finished.
-     */
-    public void onJobMapReadFinished(List<JobStatus> jobs);
-}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 3b52baf..587f596 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -69,7 +69,7 @@
  * @hide
  */
 public class JobSchedulerService extends com.android.server.SystemService
-        implements StateChangedListener, JobCompletedListener, JobMapReadFinishedListener {
+        implements StateChangedListener, JobCompletedListener {
     // TODO: Switch this off for final version.
     static final boolean DEBUG = true;
     /** The number of concurrent jobs we run at one time. */
@@ -487,28 +487,6 @@
         mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
     }
 
-    /**
-     * Disk I/O is finished, take the list of jobs we read from disk and add them to our
-     * {@link JobStore}.
-     * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread,
-     * and is called once at boot.
-     */
-    @Override
-    public void onJobMapReadFinished(List<JobStatus> jobs) {
-        synchronized (mJobs) {
-            for (int i=0; i<jobs.size(); i++) {
-                JobStatus js = jobs.get(i);
-                if (mJobs.containsJobIdForUid(js.getJobId(), js.getUid())) {
-                    // An app with BOOT_COMPLETED *might* have decided to reschedule their job, in
-                    // the same amount of time it took us to read it from disk. If this is the case
-                    // we leave it be.
-                    continue;
-                }
-                startTrackingJob(js);
-            }
-        }
-    }
-
     private class JobHandler extends Handler {
 
         public JobHandler(Looper looper) {
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index eaf5480..ee45833 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -285,7 +285,7 @@
                 case MSG_CALLBACK:
                     if (DEBUG) {
                         Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob + " v:" +
-                                VERB_STRINGS[mVerb]);
+                                (mVerb >= 0 ? VERB_STRINGS[mVerb] : "[invalid]"));
                     }
                     removeMessages(MSG_TIMEOUT);
 
@@ -518,7 +518,7 @@
                     EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
             if (DEBUG) {
                 Slog.d(TAG, "Scheduling time out for '" +
-                        mRunningJob.getServiceComponent().getShortClassName() + "' tId: " +
+                        mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
                         mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
             }
             Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 48312b0..46f557f 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -88,19 +88,26 @@
         synchronized (sSingletonLock) {
             if (sSingleton == null) {
                 sSingleton = new JobStore(jobManagerService.getContext(),
-                        Environment.getDataDirectory(), jobManagerService);
+                        Environment.getDataDirectory());
             }
             return sSingleton;
         }
     }
 
+    /**
+     * @return A freshly initialized job store object, with no loaded jobs.
+     */
     @VisibleForTesting
-    public static JobStore initAndGetForTesting(Context context, File dataDir,
-                                                 JobMapReadFinishedListener callback) {
-        return new JobStore(context, dataDir, callback);
+    public static JobStore initAndGetForTesting(Context context, File dataDir) {
+        JobStore jobStoreUnderTest = new JobStore(context, dataDir);
+        jobStoreUnderTest.clear();
+        return jobStoreUnderTest;
     }
 
-    private JobStore(Context context, File dataDir, JobMapReadFinishedListener callback) {
+    /**
+     * Construct the instance of the job store. This results in a blocking read from disk.
+     */
+    private JobStore(Context context, File dataDir) {
         mContext = context;
         mDirtyOperations = 0;
 
@@ -111,7 +118,7 @@
 
         mJobSet = new ArraySet<JobStatus>();
 
-        readJobMapFromDiskAsync(callback);
+        readJobMapFromDisk(mJobSet);
     }
 
     /**
@@ -249,12 +256,9 @@
         }
     }
 
-    private void readJobMapFromDiskAsync(JobMapReadFinishedListener callback) {
-        mIoHandler.post(new ReadJobMapFromDiskRunnable(callback));
-    }
-
-    public void readJobMapFromDisk(JobMapReadFinishedListener callback) {
-        new ReadJobMapFromDiskRunnable(callback).run();
+    @VisibleForTesting
+    public void readJobMapFromDisk(ArraySet<JobStatus> jobSet) {
+        new ReadJobMapFromDiskRunnable(jobSet).run();
     }
 
     /**
@@ -398,13 +402,18 @@
     }
 
     /**
-     * Runnable that reads list of persisted job from xml.
-     * NOTE: This Runnable locks on JobStore.this
+     * Runnable that reads list of persisted job from xml. This is run once at start up, so doesn't
+     * need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}.
      */
     private class ReadJobMapFromDiskRunnable implements Runnable {
-        private JobMapReadFinishedListener mCallback;
-        public ReadJobMapFromDiskRunnable(JobMapReadFinishedListener callback) {
-            mCallback = callback;
+        private final ArraySet<JobStatus> jobSet;
+
+        /**
+         * @param jobSet Reference to the (empty) set of JobStatus objects that back the JobStore,
+         *               so that after disk read we can populate it directly.
+         */
+        ReadJobMapFromDiskRunnable(ArraySet<JobStatus> jobSet) {
+            this.jobSet = jobSet;
         }
 
         @Override
@@ -414,11 +423,13 @@
                 FileInputStream fis = mJobsFile.openRead();
                 synchronized (JobStore.this) {
                     jobs = readJobMapImpl(fis);
+                    if (jobs != null) {
+                        for (int i=0; i<jobs.size(); i++) {
+                            this.jobSet.add(jobs.get(i));
+                        }
+                    }
                 }
                 fis.close();
-                if (jobs != null) {
-                    mCallback.onJobMapReadFinished(jobs);
-                }
             } catch (FileNotFoundException e) {
                 if (JobSchedulerService.DEBUG) {
                     Slog.d(TAG, "Could not find jobs file, probably there was nothing to load.");
@@ -673,4 +684,4 @@
             return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 07ffe4d..2213934 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -137,6 +137,9 @@
             filter.addAction(Intent.ACTION_DREAMING_STARTED);
             filter.addAction(Intent.ACTION_DREAMING_STOPPED);
 
+            // Debugging/instrumentation
+            filter.addAction(ACTION_TRIGGER_IDLE);
+
             mContext.registerReceiver(this, filter);
         }
 
@@ -181,6 +184,16 @@
 
     @Override
     public void dumpControllerState(PrintWriter pw) {
-
+        synchronized (mTrackedTasks) {
+            pw.print("Idle: ");
+            pw.println(mIdleTracker.isIdle() ? "true" : "false");
+            pw.println(mTrackedTasks.size());
+            for (int i = 0; i < mTrackedTasks.size(); i++) {
+                final JobStatus js = mTrackedTasks.get(i);
+                pw.print("  ");
+                pw.print(String.valueOf(js.hashCode()).substring(0, 3));
+                pw.println("..");
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 09873c7..058a23e 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -38,6 +38,7 @@
 import android.location.Criteria;
 import android.location.FusedBatchOptions;
 import android.location.GpsMeasurementsEvent;
+import android.location.GpsNavigationMessageEvent;
 import android.location.IGpsGeofenceHardware;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
@@ -324,6 +325,14 @@
         protected boolean isSupported() {
             return GpsLocationProvider.isSupported();
         }
+
+        @Override
+        protected boolean registerWithService() {
+            return true;
+        }
+
+        @Override
+        protected void unregisterFromService() {}
     };
 
     // Handler for processing events
@@ -374,16 +383,34 @@
         }
 
         @Override
-        protected void onFirstListenerAdded() {
-            native_start_measurement_collection();
+        protected boolean registerWithService() {
+            return native_start_measurement_collection();
         }
 
         @Override
-        protected void onLastListenerRemoved() {
+        protected void unregisterFromService() {
             native_stop_measurement_collection();
         }
     };
 
+    private final GpsNavigationMessageProvider mGpsNavigationMessageProvider =
+            new GpsNavigationMessageProvider() {
+        @Override
+        protected boolean isSupported() {
+            return native_is_navigation_message_supported();
+        }
+
+        @Override
+        protected boolean registerWithService() {
+            return native_start_navigation_message_collection();
+        }
+
+        @Override
+        protected void unregisterFromService() {
+            native_stop_navigation_message_collection();
+        }
+    };
+
     public IGpsStatusProvider getGpsStatusProvider() {
         return mGpsStatusProvider;
     }
@@ -396,6 +423,10 @@
         return mGpsMeasurementsProvider;
     }
 
+    public GpsNavigationMessageProvider getGpsNavigationMessageProvider() {
+        return mGpsNavigationMessageProvider;
+    }
+
     private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -1357,13 +1388,20 @@
     }
 
     /**
-     * called from native code - Gps Data callback
+     * called from native code - Gps measurements callback
      */
     private void reportMeasurementData(GpsMeasurementsEvent event) {
         mGpsMeasurementsProvider.onMeasurementsAvailable(event);
     }
 
     /**
+     * called from native code - GPS navigation message callback
+     */
+    private void reportNavigationMessage(GpsNavigationMessageEvent event) {
+        mGpsNavigationMessageProvider.onNavigationMessageAvailable(event);
+    }
+
+    /**
      * called from native code to inform us what the GPS engine capabilities are
      */
     private void setEngineCapabilities(int capabilities) {
@@ -1954,6 +1992,11 @@
 
     // Gps Hal measurements support.
     private static native boolean native_is_measurement_supported();
-    private static native boolean native_start_measurement_collection();
-    private static native boolean native_stop_measurement_collection();
+    private native boolean native_start_measurement_collection();
+    private native boolean native_stop_measurement_collection();
+
+    // Gps Navigation message support.
+    private static native boolean native_is_navigation_message_supported();
+    private native boolean native_start_navigation_message_collection();
+    private native boolean native_stop_navigation_message_collection();
 }
diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
index 001f638..1c48257 100644
--- a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
@@ -29,6 +29,9 @@
  */
 public abstract class GpsMeasurementsProvider
         extends RemoteListenerHelper<IGpsMeasurementsListener> {
+    public GpsMeasurementsProvider() {
+        super("GpsMeasurementsProvider");
+    }
 
     public void onMeasurementsAvailable(final GpsMeasurementsEvent event) {
         ListenerOperation<IGpsMeasurementsListener> operation =
diff --git a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
new file mode 100644
index 0000000..fca7378
--- /dev/null
+++ b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.location;
+
+import android.location.GpsNavigationMessageEvent;
+import android.location.IGpsNavigationMessageListener;
+import android.os.RemoteException;
+
+/**
+ * An base implementation for GPS navigation messages provider.
+ * It abstracts out the responsibility of handling listeners, while still allowing technology
+ * specific implementations to be built.
+ *
+ * @hide
+ */
+public abstract class GpsNavigationMessageProvider
+        extends RemoteListenerHelper<IGpsNavigationMessageListener> {
+    public GpsNavigationMessageProvider() {
+        super("GpsNavigationMessageProvider");
+    }
+
+    public void onNavigationMessageAvailable(final GpsNavigationMessageEvent event) {
+        ListenerOperation<IGpsNavigationMessageListener> operation =
+                new ListenerOperation<IGpsNavigationMessageListener>() {
+                    @Override
+                    public void execute(IGpsNavigationMessageListener listener)
+                            throws RemoteException {
+                        listener.onGpsNavigationMessageReceived(event);
+                    }
+                };
+
+        foreach(operation);
+    }
+}
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
index b741e75..27cf3d8 100644
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
@@ -23,6 +23,10 @@
  * Implementation of a handler for {@link IGpsStatusListener}.
  */
 abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
+    public GpsStatusListenerHelper() {
+        super("GpsStatusListenerHelper");
+    }
+
     public void onFirstFix(final int timeToFirstFix) {
         Operation operation = new Operation() {
             @Override
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 79335f7..451af18 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -32,16 +32,19 @@
  * A helper class, that handles operations in remote listeners, and tracks for remote process death.
  */
 abstract class RemoteListenerHelper<TListener extends IInterface> {
-    private static final String TAG = "RemoteListenerHelper";
-
+    private final String mTag;
     private final HashMap<IBinder, LinkedListener> mListenerMap =
             new HashMap<IBinder, LinkedListener>();
 
+    protected RemoteListenerHelper(String name) {
+        Preconditions.checkNotNull(name);
+        mTag = name;
+    }
+
     public boolean addListener(@NonNull TListener listener) {
         Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
-
         if (!isSupported()) {
-            Log.e(TAG, "Refused to add listener, the feature is not supported.");
+            Log.e(mTag, "Refused to add listener, the feature is not supported.");
             return false;
         }
 
@@ -58,13 +61,17 @@
             } catch (RemoteException e) {
                 // if the remote process registering the listener is already death, just swallow the
                 // exception and continue
-                Log.e(TAG, "Remote listener already died.", e);
+                Log.e(mTag, "Remote listener already died.", e);
                 return false;
             }
 
             mListenerMap.put(binder, deathListener);
             if (mListenerMap.size() == 1) {
-                onFirstListenerAdded();
+                if (!registerWithService()) {
+                    Log.e(mTag, "RegisterWithService failed, listener will be removed.");
+                    removeListener(listener);
+                    return false;
+                }
             }
         }
 
@@ -73,9 +80,8 @@
 
     public boolean removeListener(@NonNull TListener listener) {
         Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
-
         if (!isSupported()) {
-            Log.e(TAG, "Refused to remove listener, the feature is not supported.");
+            Log.e(mTag, "Refused to remove listener, the feature is not supported.");
             return false;
         }
 
@@ -84,26 +90,19 @@
         synchronized (mListenerMap) {
             linkedListener = mListenerMap.remove(binder);
             if (mListenerMap.isEmpty() && linkedListener != null) {
-                onLastListenerRemoved();
+                unregisterFromService();
             }
         }
 
         if (linkedListener != null) {
             binder.unlinkToDeath(linkedListener, 0 /* flags */);
         }
-
         return true;
     }
 
     protected abstract boolean isSupported();
-
-    protected void onFirstListenerAdded() {
-        // event triggered when the first listener has been added
-    }
-
-    protected void onLastListenerRemoved() {
-        // event triggered when the last listener has bee removed
-    }
+    protected abstract boolean registerWithService();
+    protected abstract void unregisterFromService();
 
     protected interface ListenerOperation<TListener extends IInterface> {
         void execute(TListener listener) throws RemoteException;
@@ -121,7 +120,7 @@
             try {
                 operation.execute(listener);
             } catch (RemoteException e) {
-                Log.e(TAG, "Error in monitored listener.", e);
+                Log.e(mTag, "Error in monitored listener.", e);
                 removeListener(listener);
             }
         }
@@ -141,7 +140,7 @@
 
         @Override
         public void binderDied() {
-            Log.d(TAG, "Remote Listener died: " + mListener);
+            Log.d(mTag, "Remote Listener died: " + mListener);
             removeListener(mListener);
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 4304b59..2f1bd60 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,26 +16,28 @@
 
 package com.android.server.media;
 
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.media.routing.IMediaRouter;
-import android.media.routing.IMediaRouterDelegate;
-import android.media.routing.IMediaRouterStateCallback;
-import android.media.session.ISessionController;
-import android.media.session.ISessionControllerCallback;
-import android.media.session.ISession;
-import android.media.session.ISessionCallback;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionInfo;
-import android.media.session.PlaybackState;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.AudioAttributes;
+import android.content.pm.ParceledListSlice;
 import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
+import android.media.routing.IMediaRouter;
+import android.media.routing.IMediaRouterDelegate;
+import android.media.routing.IMediaRouterStateCallback;
+import android.media.session.ISession;
+import android.media.session.ISessionCallback;
+import android.media.session.ISessionController;
+import android.media.session.ISessionControllerCallback;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.ParcelableVolumeInfo;
+import android.media.session.PlaybackState;
+import android.media.AudioAttributes;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.DeadObjectException;
@@ -46,15 +48,12 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
-import android.text.TextUtils;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 import android.view.KeyEvent;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.UUID;
 
 /**
@@ -82,7 +81,7 @@
     private final int mOwnerPid;
     private final int mOwnerUid;
     private final int mUserId;
-    private final MediaSessionInfo mSessionInfo;
+    private final String mPackageName;
     private final String mTag;
     private final ControllerStub mController;
     private final SessionStub mSession;
@@ -95,12 +94,16 @@
 
     private long mFlags;
     private IMediaRouter mMediaRouter;
-    private ComponentName mMediaButtonReceiver;
+    private PendingIntent mMediaButtonReceiver;
+    private PendingIntent mLaunchIntent;
 
     // TransportPerformer fields
 
+    private Bundle mExtras;
     private MediaMetadata mMetadata;
     private PlaybackState mPlaybackState;
+    private ParceledListSlice mQueue;
+    private CharSequence mQueueTitle;
     private int mRatingType;
     private long mLastActiveTime;
     // End TransportPerformer fields
@@ -123,8 +126,7 @@
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
-        mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName,
-                ownerPid);
+        mPackageName = ownerPackageName;
         mTag = tag;
         mController = new ControllerStub();
         mSession = new SessionStub();
@@ -158,11 +160,25 @@
      *
      * @return Info that identifies this session.
      */
-    public MediaSessionInfo getSessionInfo() {
-        return mSessionInfo;
+    public String getPackageName() {
+        return mPackageName;
     }
 
-    public ComponentName getMediaButtonReceiver() {
+    /**
+     * Get the tag for the session.
+     *
+     * @return The session's tag.
+     */
+    public String getTag() {
+        return mTag;
+    }
+
+    /**
+     * Get the intent the app set for their media button receiver.
+     *
+     * @return The pending intent set by the app or null.
+     */
+    public PendingIntent getMediaButtonReceiver() {
         return mMediaButtonReceiver;
     }
 
@@ -396,9 +412,10 @@
         pw.println(prefix + mTag + " " + this);
 
         final String indent = prefix + "  ";
+        // We print the hashcode for matching with the list in user records
         pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
                 + ", userId=" + mUserId);
-        pw.println(indent + "info=" + mSessionInfo.toString());
+        pw.println(indent + "package=" + mPackageName);
         pw.println(indent + "active=" + mIsActive);
         pw.println(indent + "flags=" + mFlags);
         pw.println(indent + "rating type=" + mRatingType);
@@ -407,6 +424,11 @@
         pw.println(indent + "metadata:" + getShortMetadataString());
     }
 
+    @Override
+    public String toString() {
+        return mPackageName + "/" + mTag;
+    }
+
     private String getShortMetadataString() {
         int fields = mMetadata == null ? 0 : mMetadata.size();
         String title = mMetadata == null ? null : mMetadata
@@ -452,6 +474,63 @@
         }
     }
 
+    private void pushQueueUpdate() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+                try {
+                    cb.onQueueChanged(mQueue);
+                } catch (DeadObjectException e) {
+                    mControllerCallbacks.remove(i);
+                    Log.w(TAG, "Removed dead callback in pushQueueUpdate.", e);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "unexpected exception in pushQueueUpdate.", e);
+                }
+            }
+        }
+    }
+
+    private void pushQueueTitleUpdate() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+                try {
+                    cb.onQueueTitleChanged(mQueueTitle);
+                } catch (DeadObjectException e) {
+                    mControllerCallbacks.remove(i);
+                    Log.w(TAG, "Removed dead callback in pushQueueTitleUpdate.", e);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "unexpected exception in pushQueueTitleUpdate.", e);
+                }
+            }
+        }
+    }
+
+    private void pushExtrasUpdate() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+                try {
+                    cb.onExtrasChanged(mExtras);
+                } catch (DeadObjectException e) {
+                    mControllerCallbacks.remove(i);
+                    Log.w(TAG, "Removed dead callback in pushExtrasUpdate.", e);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "unexpected exception in pushExtrasUpdate.", e);
+                }
+            }
+        }
+    }
+
     private void pushVolumeUpdate() {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -583,8 +662,13 @@
         }
 
         @Override
-        public void setMediaButtonReceiver(ComponentName mbr) {
-            mMediaButtonReceiver = mbr;
+        public void setMediaButtonReceiver(PendingIntent pi) {
+            mMediaButtonReceiver = pi;
+        }
+
+        @Override
+        public void setLaunchPendingIntent(PendingIntent pi) {
+            mLaunchIntent = pi;
         }
 
         @Override
@@ -606,6 +690,24 @@
         }
 
         @Override
+        public void setQueue(ParceledListSlice queue) {
+            mQueue = queue;
+            mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
+        }
+
+        @Override
+        public void setQueueTitle(CharSequence title) {
+            mQueueTitle = title;
+            mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
+        }
+
+        @Override
+        public void setExtras(Bundle extras) {
+            mExtras = extras;
+            mHandler.post(MessageHandler.MSG_UPDATE_EXTRAS);
+        }
+
+        @Override
         public void setRatingType(int type) {
             mRatingType = type;
         }
@@ -667,14 +769,22 @@
             return false;
         }
 
-        public void sendCommand(String command, Bundle extras, ResultReceiver cb) {
+        public void sendCommand(String command, Bundle args, ResultReceiver cb) {
             try {
-                mCb.onCommand(command, extras, cb);
+                mCb.onCommand(command, args, cb);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendCommand.", e);
             }
         }
 
+        public void sendCustomAction(String action, Bundle args) {
+            try {
+                mCb.onCustomAction(action, args);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in sendCustomAction.", e);
+            }
+        }
+
         public void play() {
             try {
                 mCb.onPlay();
@@ -683,6 +793,30 @@
             }
         }
 
+        public void playUri(Uri uri, Bundle extras) {
+            try {
+                mCb.onPlayUri(uri, extras);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in playUri.", e);
+            }
+        }
+
+        public void playFromSearch(String query, Bundle extras) {
+            try {
+                mCb.onPlayFromSearch(query, extras);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in playFromSearch.", e);
+            }
+        }
+
+        public void skipToTrack(long id) {
+            try {
+                mCb.onSkipToTrack(id);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in skipToTrack", e);
+            }
+        }
+
         public void pause() {
             try {
                 mCb.onPause();
@@ -766,9 +900,9 @@
 
     class ControllerStub extends ISessionController.Stub {
         @Override
-        public void sendCommand(String command, Bundle extras, ResultReceiver cb)
+        public void sendCommand(String command, Bundle args, ResultReceiver cb)
                 throws RemoteException {
-            mSessionCb.sendCommand(command, extras, cb);
+            mSessionCb.sendCommand(command, args, cb);
         }
 
         @Override
@@ -803,8 +937,18 @@
         }
 
         @Override
-        public MediaSessionInfo getSessionInfo() {
-            return mSessionInfo;
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        @Override
+        public String getTag() {
+            return mTag;
+        }
+
+        @Override
+        public PendingIntent getLaunchPendingIntent() {
+            return mLaunchIntent;
         }
 
         @Override
@@ -859,6 +1003,22 @@
         }
 
         @Override
+        public void playUri(Uri uri, Bundle extras) throws RemoteException {
+            mSessionCb.playUri(uri, extras);
+        }
+
+        @Override
+        public void playFromSearch(String query, Bundle extras) throws RemoteException {
+            mSessionCb.playFromSearch(query, extras);
+        }
+
+        @Override
+        public void skipToTrack(long id) {
+            mSessionCb.skipToTrack(id);
+        }
+
+
+        @Override
         public void pause() throws RemoteException {
             mSessionCb.pause();
         }
@@ -898,6 +1058,12 @@
             mSessionCb.rate(rating);
         }
 
+        @Override
+        public void sendCustomAction(String action, Bundle args)
+                throws RemoteException {
+            mSessionCb.sendCustomAction(action, args);
+        }
+
 
         @Override
         public MediaMetadata getMetadata() {
@@ -910,6 +1076,21 @@
         }
 
         @Override
+        public ParceledListSlice getQueue() {
+            return mQueue;
+        }
+
+        @Override
+        public CharSequence getQueueTitle() {
+            return mQueueTitle;
+        }
+
+        @Override
+        public Bundle getExtras() {
+            return mExtras;
+        }
+
+        @Override
         public int getRatingType() {
             return mRatingType;
         }
@@ -930,9 +1111,12 @@
     private class MessageHandler extends Handler {
         private static final int MSG_UPDATE_METADATA = 1;
         private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
-        private static final int MSG_SEND_EVENT = 3;
-        private static final int MSG_UPDATE_SESSION_STATE = 4;
-        private static final int MSG_UPDATE_VOLUME = 5;
+        private static final int MSG_UPDATE_QUEUE = 3;
+        private static final int MSG_UPDATE_QUEUE_TITLE = 4;
+        private static final int MSG_UPDATE_EXTRAS = 5;
+        private static final int MSG_SEND_EVENT = 6;
+        private static final int MSG_UPDATE_SESSION_STATE = 7;
+        private static final int MSG_UPDATE_VOLUME = 8;
 
         public MessageHandler(Looper looper) {
             super(looper);
@@ -946,6 +1130,15 @@
                 case MSG_UPDATE_PLAYBACK_STATE:
                     pushPlaybackStateUpdate();
                     break;
+                case MSG_UPDATE_QUEUE:
+                    pushQueueUpdate();
+                    break;
+                case MSG_UPDATE_QUEUE_TITLE:
+                    pushQueueTitleUpdate();
+                    break;
+                case MSG_UPDATE_EXTRAS:
+                    pushExtrasUpdate();
+                    break;
                 case MSG_SEND_EVENT:
                     pushEvent((String) msg.obj, msg.getData());
                     break;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b0ccd62..92644ce 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -20,6 +20,8 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -407,16 +409,6 @@
         return user;
     }
 
-    private int findIndexOfSessionForIdLocked(String sessionId) {
-        for (int i = mAllSessions.size() - 1; i >= 0; i--) {
-            MediaSessionRecord session = mAllSessions.get(i);
-            if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
     private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
         for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
             if (mSessionsListeners.get(i).mListener == listener) {
@@ -436,7 +428,7 @@
             List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId);
             int size = records.size();
             if (size > 0) {
-                persistMediaButtonReceiverLocked(records.get(0));
+                rememberMediaButtonReceiverLocked(records.get(0));
             }
             ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
             for (int i = 0; i < size; i++) {
@@ -469,13 +461,11 @@
         }
     }
 
-    private void persistMediaButtonReceiverLocked(MediaSessionRecord record) {
-        ComponentName receiver = record.getMediaButtonReceiver();
-        if (receiver != null) {
-            Settings.System.putStringForUser(mContentResolver,
-                    Settings.System.MEDIA_BUTTON_RECEIVER,
-                    receiver == null ? "" : receiver.flattenToString(),
-                    UserHandle.USER_CURRENT);
+    private void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
+        PendingIntent receiver = record.getMediaButtonReceiver();
+        UserRecord user = mUserRecords.get(record.getUserId());
+        if (receiver != null && user != null) {
+            user.mLastMediaButtonReceiver = receiver;
         }
     }
 
@@ -486,6 +476,7 @@
     final class UserRecord {
         private final int mUserId;
         private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+        private PendingIntent mLastMediaButtonReceiver;
 
         public UserRecord(Context context, int userId) {
             mUserId = userId;
@@ -521,12 +512,13 @@
         public void dumpLocked(PrintWriter pw, String prefix) {
             pw.println(prefix + "Record for user " + mUserId);
             String indent = prefix + "  ";
+            pw.println(indent + "MediaButtonReceiver:" + mLastMediaButtonReceiver);
             int size = mSessions.size();
             pw.println(indent + size + " Sessions:");
             for (int i = 0; i < size; i++) {
-                // Just print the session info, the full session dump will
+                // Just print the short version, the full session dump will
                 // already be in the list of all sessions.
-                pw.println(indent + mSessions.get(i).getSessionInfo());
+                pw.println(indent + mSessions.get(i).toString());
             }
         }
     }
@@ -767,9 +759,9 @@
         private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
                 MediaSessionRecord session) {
             if (DEBUG) {
-                String sessionInfo = session == null ? null : session.getSessionInfo().toString();
-                Log.d(TAG, "Adjusting session " + sessionInfo + " by " + direction + ". flags=" + flags
-                        + ", suggestedStream=" + suggestedStream);
+                String description = session == null ? null : session.toString();
+                Log.d(TAG, "Adjusting session " + description + " by " + direction + ". flags="
+                        + flags + ", suggestedStream=" + suggestedStream);
 
             }
             if (session == null) {
@@ -832,7 +824,7 @@
                 MediaSessionRecord session) {
             if (session != null) {
                 if (DEBUG) {
-                    Log.d(TAG, "Sending media key to " + session.getSessionInfo());
+                    Log.d(TAG, "Sending media key to " + session.toString());
                 }
                 if (needWakeLock) {
                     mKeyEventReceiver.aquireWakeLockLocked();
@@ -843,21 +835,43 @@
                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                         mKeyEventReceiver);
             } else {
-                if (needWakeLock) {
-                    mMediaEventWakeLock.acquire();
+                // Launch the last PendingIntent we had with priority
+                int userId = ActivityManager.getCurrentUser();
+                UserRecord user = mUserRecords.get(userId);
+                if (user.mLastMediaButtonReceiver != null) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Sending media key to last known PendingIntent");
+                    }
+                    if (needWakeLock) {
+                        mKeyEventReceiver.aquireWakeLockLocked();
+                    }
+                    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                    mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                    try {
+                        user.mLastMediaButtonReceiver.send(getContext(),
+                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                                mediaButtonIntent, mKeyEventReceiver, null);
+                    } catch (CanceledException e) {
+                        Log.i(TAG, "Error sending key event to media button receiver "
+                                + user.mLastMediaButtonReceiver, e);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "Sending media key ordered broadcast");
+                    }
+                    if (needWakeLock) {
+                        mMediaEventWakeLock.acquire();
+                    }
+                    // Fallback to legacy behavior
+                    Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+                    keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                    if (needWakeLock) {
+                        keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
+                                WAKELOCK_RELEASE_ON_FINISHED);
+                    }
+                    getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                            null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
                 }
-                if (DEBUG) {
-                    Log.d(TAG, "Sending media key ordered broadcast");
-                }
-                // Fallback to legacy behavior
-                Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-                keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-                if (needWakeLock) {
-                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
-                            WAKELOCK_RELEASE_ON_FINISHED);
-                }
-                getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                        null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
             }
         }
 
@@ -904,7 +918,8 @@
 
         private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
 
-        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable {
+        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
+                PendingIntent.OnFinished {
             private final Handler mHandler;
             private int mRefCount = 0;
             private int mLastTimeoutId = 0;
@@ -963,6 +978,12 @@
                 mMediaEventWakeLock.release();
                 mHandler.removeCallbacks(this);
             }
+
+            @Override
+            public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
+                    String resultData, Bundle resultExtras) {
+                onReceiveResult(resultCode, null);
+            }
         };
 
         BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a6711c3..f117f99 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -740,6 +740,13 @@
     private SettingsObserver mSettingsObserver;
     private ZenModeHelper mZenModeHelper;
 
+    private final Runnable mBuzzBeepBlinked = new Runnable() {
+        @Override
+        public void run() {
+            mStatusBar.buzzBeepBlinked();
+        }
+    };
+
     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
         int[] ar = r.getIntArray(resid);
         if (ar == null) {
@@ -1645,6 +1652,7 @@
     }
 
     private void buzzBeepBlinkLocked(NotificationRecord record) {
+        boolean buzzBeepBlinked = false;
         final Notification notification = record.sbn.getNotification();
 
         // Should this notification make noise, vibe, or use the LED?
@@ -1726,6 +1734,7 @@
                                     + " on stream " + audioStreamType);
                             player.playAsync(soundUri, record.sbn.getUser(), looping,
                                     audioStreamType);
+                            buzzBeepBlinked = true;
                         }
                     } catch (RemoteException e) {
                     } finally {
@@ -1765,6 +1774,7 @@
                                 : mFallbackVibrationPattern,
                             ((notification.flags & Notification.FLAG_INSISTENT) != 0)
                                 ? 0: -1, audioAttributesForNotification(notification));
+                        buzzBeepBlinked = true;
                     } finally {
                         Binder.restoreCallingIdentity(identity);
                     }
@@ -1775,6 +1785,7 @@
                             notification.vibrate,
                         ((notification.flags & Notification.FLAG_INSISTENT) != 0)
                                 ? 0: -1, audioAttributesForNotification(notification));
+                    buzzBeepBlinked = true;
                 }
             }
         }
@@ -1791,9 +1802,13 @@
             if (mUseAttentionLight) {
                 mAttentionLight.pulse();
             }
+            buzzBeepBlinked = true;
         } else if (wasShowLights) {
             updateLightsLocked();
         }
+        if (buzzBeepBlinked) {
+            mHandler.post(mBuzzBeepBlinked);
+        }
     }
 
     private static AudioAttributes audioAttributesForNotification(Notification n) {
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 81f64b1..3069ad9 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -30,6 +30,8 @@
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
 
 public class ZenLog {
     private static final String TAG = "ZenLog";
@@ -41,6 +43,10 @@
     private static final String[] MSGS = new String[SIZE];
 
     private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+    private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList(
+            "android",
+            "com.android.systemui"
+            ));
 
     private static final int TYPE_INTERCEPTED = 1;
     private static final int TYPE_ALLOW_DISABLE = 2;
@@ -61,6 +67,7 @@
     }
 
     public static void traceAllowDisable(String pkg, boolean allowDisable, String reason) {
+        if (SYSTEM_PACKAGES.contains(pkg)) return;
         append(TYPE_ALLOW_DISABLE, allowDisable + "," + pkg + "," + reason);
     }
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a896550..1289cf7 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -37,7 +37,9 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
 import android.service.notification.ZenModeConfig;
 import android.telecomm.TelecommManager;
 import android.util.Slog;
@@ -53,11 +55,9 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.Objects;
 
 /**
  * NotificationManagerService helper for functionality related to zen mode.
@@ -84,17 +84,6 @@
     private AudioManager mAudioManager;
     private int mPreviousRingerMode = -1;
 
-    // temporary, until we update apps to provide metadata
-    private static final Set<String> MESSAGE_PACKAGES = new HashSet<String>(Arrays.asList(
-            "com.google.android.talk",
-            "com.android.mms",
-            "com.android.example.notificationshowcase"
-            ));
-    private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList(
-            "android",
-            "com.android.systemui"
-            ));
-
     public ZenModeHelper(Context context, Handler handler) {
         mContext = context;
         mHandler = handler;
@@ -249,9 +238,7 @@
             allowDisable = mZenMode == Global.ZEN_MODE_OFF || mConfig.allowCalls;
             reason = mZenMode == Global.ZEN_MODE_OFF ? "zenOff" : "allowCalls";
         }
-        if (!SYSTEM_PACKAGES.contains(pkg)) {
-            ZenLog.traceAllowDisable(pkg, allowDisable, reason);
-        }
+        ZenLog.traceAllowDisable(pkg, allowDisable, reason);
         return allowDisable;
     }
 
@@ -305,8 +292,7 @@
     }
 
     private boolean isSystem(NotificationRecord record) {
-        return SYSTEM_PACKAGES.contains(record.sbn.getPackageName())
-                && record.isCategory(Notification.CATEGORY_SYSTEM);
+        return record.isCategory(Notification.CATEGORY_SYSTEM);
     }
 
     private boolean isAlarm(NotificationRecord record) {
@@ -330,8 +316,16 @@
                 && pkg.equals(mDefaultPhoneApp.getPackageName());
     }
 
+    private boolean isDefaultMessagingApp(NotificationRecord record) {
+        final int userId = record.getUserId();
+        if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
+        final String defaultApp = Secure.getStringForUser(mContext.getContentResolver(),
+                Secure.SMS_DEFAULT_APPLICATION, userId);
+        return Objects.equals(defaultApp, record.sbn.getPackageName());
+    }
+
     private boolean isMessage(NotificationRecord record) {
-        return MESSAGE_PACKAGES.contains(record.sbn.getPackageName());
+        return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record);
     }
 
     private boolean audienceMatches(NotificationRecord record) {
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
index 3ce19c1f..c61d344 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
@@ -33,17 +33,24 @@
 class CrossProfileIntentFilter extends IntentFilter {
     private static final String ATTR_TARGET_USER_ID = "targetUserId";
     private static final String ATTR_FLAGS = "flags";
+    private static final String ATTR_OWNER_USER_ID = "ownerUserId";
+    private static final String ATTR_OWNER_PACKAGE = "ownerPackage";
     private static final String ATTR_FILTER = "filter";
 
     private static final String TAG = "CrossProfileIntentFilter";
 
     // If the intent matches the IntentFilter, then it can be forwarded to this userId.
     final int mTargetUserId;
+    final int mOwnerUserId; // userId of the app which has set this CrossProfileIntentFilter.
+    final String mOwnerPackage; // packageName of the app.
     final int mFlags;
 
-    CrossProfileIntentFilter(IntentFilter filter, int targetUserId, int flags) {
+    CrossProfileIntentFilter(IntentFilter filter, String ownerPackage, int ownerUserId,
+            int targetUserId, int flags) {
         super(filter);
         mTargetUserId = targetUserId;
+        mOwnerUserId = ownerUserId;
+        mOwnerPackage = ownerPackage;
         mFlags = flags;
     }
 
@@ -55,25 +62,20 @@
         return mFlags;
     }
 
+    public int getOwnerUserId() {
+        return mOwnerUserId;
+    }
+
+    public String getOwnerPackage() {
+        return mOwnerPackage;
+    }
+
     CrossProfileIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
-        String targetUserIdString = parser.getAttributeValue(null, ATTR_TARGET_USER_ID);
-        if (targetUserIdString == null) {
-            String msg = "Missing element under " + TAG +": " + ATTR_TARGET_USER_ID + " at " +
-                    parser.getPositionDescription();
-            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
-            mTargetUserId = UserHandle.USER_NULL;
-        } else {
-            mTargetUserId = Integer.parseInt(targetUserIdString);
-        }
-        String flagsString = parser.getAttributeValue(null, ATTR_FLAGS);
-        if (flagsString == null) {
-            String msg = "Missing element under " + TAG +": " + ATTR_FLAGS + " at " +
-                    parser.getPositionDescription();
-            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
-            mFlags = 0;
-        } else {
-            mFlags = Integer.parseInt(flagsString);
-        }
+        mTargetUserId = getIntFromXml(parser, ATTR_TARGET_USER_ID, UserHandle.USER_NULL);
+        mOwnerUserId = getIntFromXml(parser, ATTR_OWNER_USER_ID, UserHandle.USER_NULL);
+        mOwnerPackage = getStringFromXml(parser, ATTR_OWNER_PACKAGE, "");
+        mFlags = getIntFromXml(parser, ATTR_FLAGS, 0);
+
         int outerDepth = parser.getDepth();
         String tagName = parser.getName();
         int type;
@@ -103,9 +105,31 @@
         }
     }
 
+    String getStringFromXml(XmlPullParser parser, String attribute, String defaultValue) {
+        String value = parser.getAttributeValue(null, attribute);
+        if (value == null) {
+            String msg = "Missing element under " + TAG +": " + attribute + " at " +
+                    parser.getPositionDescription();
+            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+            return defaultValue;
+        } else {
+            return value;
+        }
+    }
+
+    int getIntFromXml(XmlPullParser parser, String attribute, int defaultValue) {
+        String stringValue = getStringFromXml(parser, attribute, null);
+        if (stringValue != null) {
+            return Integer.parseInt(stringValue);
+        }
+        return defaultValue;
+    }
+
     public void writeToXml(XmlSerializer serializer) throws IOException {
         serializer.attribute(null, ATTR_TARGET_USER_ID, Integer.toString(mTargetUserId));
         serializer.attribute(null, ATTR_FLAGS, Integer.toString(mFlags));
+        serializer.attribute(null, ATTR_OWNER_USER_ID, Integer.toString(mOwnerUserId));
+        serializer.attribute(null, ATTR_OWNER_PACKAGE, mOwnerPackage);
         serializer.startTag(null, ATTR_FILTER);
             super.writeToXml(serializer);
         serializer.endTag(null, ATTR_FILTER);
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 09cf392..b7b1c23 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -29,6 +29,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IInterface;
@@ -36,6 +37,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
 
@@ -307,6 +309,30 @@
             }
         }
 
+        @Override
+        public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds,
+                Bundle opts, UserHandle user) throws RemoteException {
+            ensureInUserProfiles(user, "Cannot show app details for unrelated profile " + user);
+            if (!isUserEnabled(user)) {
+                throw new IllegalStateException("Cannot show app details for disabled profile "
+                        + user);
+            }
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                String packageName = component.getPackageName();
+                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+                        Uri.fromParts("package", packageName, null));
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
+                        Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                intent.setSourceBounds(sourceBounds);
+                mContext.startActivityAsUser(intent, opts, user);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+
         private class MyPackageMonitor extends PackageMonitor {
 
             /** Checks if user is a profile of or same as listeningUser.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index db915e2..6036bcf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -24,10 +24,11 @@
 import android.content.Context;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstaller;
-import android.content.pm.IPackageInstallerObserver;
+import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.InstallSessionInfo;
 import android.content.pm.InstallSessionParams;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.FileUtils;
 import android.os.HandlerThread;
@@ -54,6 +55,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 public class PackageInstallerService extends IPackageInstaller.Stub {
     private static final String TAG = "PackageInstaller";
@@ -80,7 +82,7 @@
     @GuardedBy("mSessions")
     private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
 
-    private RemoteCallbackList<IPackageInstallerObserver> mObservers = new RemoteCallbackList<>();
+    private RemoteCallbackList<IPackageInstallerCallback> mCallbacks = new RemoteCallbackList<>();
 
     private static final FilenameFilter sStageFilter = new FilenameFilter() {
         @Override
@@ -152,8 +154,7 @@
     }
 
     @Override
-    public int createSession(String installerPackageName, InstallSessionParams params,
-            int userId) {
+    public int createSession(InstallSessionParams params, String installerPackageName, int userId) {
         final int callingUid = Binder.getCallingUid();
         mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession");
 
@@ -172,14 +173,18 @@
             params.installFlags |= INSTALL_REPLACE_EXISTING;
         }
 
-        if (params.mode == InstallSessionParams.MODE_INVALID) {
-            throw new IllegalArgumentException("Params must have valid mode set");
+        switch (params.mode) {
+            case InstallSessionParams.MODE_FULL_INSTALL:
+            case InstallSessionParams.MODE_INHERIT_EXISTING:
+                break;
+            default:
+                throw new IllegalArgumentException("Params must have valid mode set");
         }
 
         // Sanity check that install could fit
-        if (params.deltaSize > 0) {
+        if (params.sizeBytes > 0) {
             try {
-                mPm.freeStorage(params.deltaSize);
+                mPm.freeStorage(params.sizeBytes);
             } catch (IOException e) {
                 throw ExceptionUtils.wrap(e);
             }
@@ -248,8 +253,22 @@
     }
 
     @Override
-    public List<InstallSessionInfo> getSessions(int userId) {
-        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getSessions");
+    public InstallSessionInfo getSessionInfo(int sessionId) {
+        synchronized (mSessions) {
+            final PackageInstallerSession session = mSessions.get(sessionId);
+            final boolean isOwner = (session != null)
+                    && (session.installerUid == Binder.getCallingUid());
+            if (!isOwner) {
+                enforceCallerCanReadSessions();
+            }
+            return session != null ? session.generateInfo() : null;
+        }
+    }
+
+    @Override
+    public List<InstallSessionInfo> getAllSessions(int userId) {
+        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions");
+        enforceCallerCanReadSessions();
 
         final List<InstallSessionInfo> result = new ArrayList<>();
         synchronized (mSessions) {
@@ -264,9 +283,29 @@
     }
 
     @Override
+    public List<InstallSessionInfo> getMySessions(String installerPackageName, int userId) {
+        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions");
+        mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
+
+        final List<InstallSessionInfo> result = new ArrayList<>();
+        synchronized (mSessions) {
+            for (int i = 0; i < mSessions.size(); i++) {
+                final PackageInstallerSession session = mSessions.valueAt(i);
+                if (Objects.equals(session.installerPackageName, installerPackageName)
+                        && session.userId == userId) {
+                    result.add(session.generateInfo());
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
     public void uninstall(String packageName, int flags, IPackageDeleteObserver observer,
             int userId) {
         mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");
+
+        // TODO: enforce installer of record or permission
         mPm.deletePackageAsUser(packageName, observer, userId, flags);
     }
 
@@ -280,17 +319,16 @@
     }
 
     @Override
-    public void registerObserver(IPackageInstallerObserver observer, int userId) {
-        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerObserver");
+    public void registerCallback(IPackageInstallerCallback callback, int userId) {
+        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback");
+        enforceCallerCanReadSessions();
 
-        // TODO: consider restricting to active launcher app only
-        mObservers.register(observer, new UserHandle(userId));
+        mCallbacks.register(callback, new UserHandle(userId));
     }
 
     @Override
-    public void unregisterObserver(IPackageInstallerObserver observer, int userId) {
-        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "unregisterObserver");
-        mObservers.unregister(observer);
+    public void unregisterCallback(IPackageInstallerCallback callback) {
+        mCallbacks.unregister(callback);
     }
 
     private int getSessionUserId(int sessionId) {
@@ -299,52 +337,68 @@
         }
     }
 
-    private void notifySessionCreated(InstallSessionInfo info) {
-        final int userId = getSessionUserId(info.sessionId);
-        final int n = mObservers.beginBroadcast();
-        for (int i = 0; i < n; i++) {
-            final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i);
-            final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i);
-            if (userId == user.getIdentifier()) {
-                try {
-                    observer.onSessionCreated(info);
-                } catch (RemoteException ignored) {
-                }
-            }
+    /**
+     * We allow those with permission, or the current home app.
+     */
+    private void enforceCallerCanReadSessions() {
+        final boolean hasPermission = (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_INSTALL_SESSIONS)
+                == PackageManager.PERMISSION_GRANTED);
+        final boolean isHomeApp = mPm.checkCallerIsHomeApp();
+        if (hasPermission || isHomeApp) {
+            return;
+        } else {
+            throw new SecurityException("Caller must be current home app to read install sessions");
         }
-        mObservers.finishBroadcast();
     }
 
-    private void notifySessionProgress(int sessionId, int progress) {
-        final int userId = getSessionUserId(sessionId);
-        final int n = mObservers.beginBroadcast();
+    private void notifySessionCreated(InstallSessionInfo info) {
+        final int userId = getSessionUserId(info.sessionId);
+        final int n = mCallbacks.beginBroadcast();
         for (int i = 0; i < n; i++) {
-            final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i);
-            final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i);
+            final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
+            final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
+            // TODO: dispatch notifications for slave profiles
             if (userId == user.getIdentifier()) {
                 try {
-                    observer.onSessionProgress(sessionId, progress);
+                    callback.onSessionCreated(info.sessionId);
                 } catch (RemoteException ignored) {
                 }
             }
         }
-        mObservers.finishBroadcast();
+        mCallbacks.finishBroadcast();
+    }
+
+    private void notifySessionProgressChanged(int sessionId, float progress) {
+        final int userId = getSessionUserId(sessionId);
+        final int n = mCallbacks.beginBroadcast();
+        for (int i = 0; i < n; i++) {
+            final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
+            final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
+            if (userId == user.getIdentifier()) {
+                try {
+                    callback.onSessionProgressChanged(sessionId, progress);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+        mCallbacks.finishBroadcast();
     }
 
     private void notifySessionFinished(int sessionId, boolean success) {
         final int userId = getSessionUserId(sessionId);
-        final int n = mObservers.beginBroadcast();
+        final int n = mCallbacks.beginBroadcast();
         for (int i = 0; i < n; i++) {
-            final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i);
-            final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i);
+            final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
+            final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
             if (userId == user.getIdentifier()) {
                 try {
-                    observer.onSessionFinished(sessionId, success);
+                    callback.onSessionFinished(sessionId, success);
                 } catch (RemoteException ignored) {
                 }
             }
         }
-        mObservers.finishBroadcast();
+        mCallbacks.finishBroadcast();
     }
 
     void dump(IndentingPrintWriter pw) {
@@ -374,8 +428,8 @@
     }
 
     class Callback {
-        public void onSessionProgress(PackageInstallerSession session, int progress) {
-            notifySessionProgress(session.sessionId, progress);
+        public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
+            notifySessionProgressChanged(session.sessionId, progress);
         }
 
         public void onSessionFinished(PackageInstallerSession session, boolean success) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0e6a3f0..06e1d53 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -71,6 +71,8 @@
     // TODO: enforce INSTALL_ALLOW_DOWNGRADE
     // TODO: handle INSTALL_EXTERNAL, INSTALL_INTERNAL
 
+    // TODO: treat INHERIT_EXISTING as installExistingPackage()
+
     private final PackageInstallerService.Callback mCallback;
     private final PackageManagerService mPm;
     private final Handler mHandler;
@@ -84,7 +86,7 @@
     public final long createdMillis;
     public final File sessionStageDir;
 
-    private static final int MSG_INSTALL = 0;
+    private static final int MSG_COMMIT = 0;
 
     private Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
@@ -95,7 +97,7 @@
                 }
 
                 try {
-                    installLocked();
+                    commitLocked();
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "Install failed: " + e);
                     destroyInternal();
@@ -114,8 +116,8 @@
 
     private final Object mLock = new Object();
 
-    private int mClientProgress;
-    private int mProgress = 0;
+    private float mClientProgress;
+    private float mProgress = 0;
 
     private String mPackageName;
     private int mVersionCode;
@@ -168,23 +170,23 @@
         info.progress = mProgress;
 
         info.mode = params.mode;
-        info.packageName = params.packageName;
-        info.icon = params.icon;
-        info.title = params.title;
+        info.sizeBytes = params.sizeBytes;
+        info.appPackageName = params.appPackageName;
+        info.appIcon = params.appIcon;
+        info.appLabel = params.appLabel;
 
         return info;
     }
 
     @Override
-    public void setClientProgress(int progress) {
+    public void setClientProgress(float progress) {
         mClientProgress = progress;
-        mProgress = MathUtils.constrain(
-                (int) (((float) mClientProgress) / ((float) params.progressMax)) * 80, 0, 80);
-        mCallback.onSessionProgress(this, mProgress);
+        mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f);
+        mCallback.onSessionProgressChanged(this, mProgress);
     }
 
     @Override
-    public void addClientProgress(int progress) {
+    public void addClientProgress(float progress) {
         setClientProgress(mClientProgress + progress);
     }
 
@@ -250,12 +252,12 @@
     }
 
     @Override
-    public void install(IPackageInstallObserver2 observer) {
+    public void commit(IPackageInstallObserver2 observer) {
         Preconditions.checkNotNull(observer);
-        mHandler.obtainMessage(MSG_INSTALL, observer).sendToTarget();
+        mHandler.obtainMessage(MSG_COMMIT, observer).sendToTarget();
     }
 
-    private void installLocked() throws PackageManagerException {
+    private void commitLocked() throws PackageManagerException {
         if (mInvalid) {
             throw new PackageManagerException(INSTALL_FAILED_ALREADY_EXISTS, "Invalid session");
         }
@@ -295,7 +297,7 @@
         }
 
         // TODO: surface more granular state from dexopt
-        mCallback.onSessionProgress(this, 90);
+        mCallback.onSessionProgressChanged(this, 0.9f);
 
         // TODO: for ASEC based applications, grow and stream in packages
 
@@ -458,7 +460,12 @@
     }
 
     @Override
-    public void destroy() {
+    public void close() {
+        // Currently ignored
+    }
+
+    @Override
+    public void abandon() {
         try {
             destroyInternal();
         } finally {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 69f2f32..68ae6ff 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -138,7 +138,6 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Environment.UserEnvironment;
-import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
@@ -235,7 +234,6 @@
     private static final boolean DEBUG_PACKAGE_INFO = false;
     private static final boolean DEBUG_INTENT_MATCHING = false;
     private static final boolean DEBUG_PACKAGE_SCANNING = false;
-    private static final boolean DEBUG_APP_DIR_OBSERVER = false;
     private static final boolean DEBUG_VERIFY = false;
     private static final boolean DEBUG_DEXOPT = false;
     private static final boolean DEBUG_ABI_SELECTION = false;
@@ -249,12 +247,6 @@
     // Cap the size of permission trees that 3rd party apps can define
     private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768;     // characters of text
 
-    private static final int REMOVE_EVENTS =
-        FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM;
-    private static final int ADD_EVENTS =
-        FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO;
-
-    private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS;
     // Suffix used during package installation when copying/moving
     // package apks to install directory.
     private static final String INSTALL_PACKAGE_SUFFIX = "-";
@@ -342,30 +334,6 @@
     /** The location for ASEC container files on internal storage. */
     final String mAsecInternalPath;
 
-    // This is the object monitoring the framework dir.
-    final FileObserver mFrameworkInstallObserver;
-
-    // This is the object monitoring the system app dir.
-    final FileObserver mSystemInstallObserver;
-
-    // This is the object monitoring the privileged system app dir.
-    final FileObserver mPrivilegedInstallObserver;
-
-    // This is the object monitoring the vendor app dir.
-    final FileObserver mVendorInstallObserver;
-
-    // This is the object monitoring the vendor overlay package dir.
-    final FileObserver mVendorOverlayInstallObserver;
-
-    // This is the object monitoring the OEM app dir.
-    final FileObserver mOemInstallObserver;
-
-    // This is the object monitoring mAppInstallDir.
-    final FileObserver mAppInstallObserver;
-
-    // This is the object monitoring mDrmAppPrivateInstallDir.
-    final FileObserver mDrmAppInstallObserver;
-
     // Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
     // LOCK HELD.  Can be called with mInstallLock held.
     final Installer mInstaller;
@@ -1542,16 +1510,10 @@
             // For security and version matching reason, only consider
             // overlay packages if they reside in VENDOR_OVERLAY_DIR.
             File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
-            mVendorOverlayInstallObserver = new AppDirObserver(
-                    vendorOverlayDir.getPath(), OBSERVER_EVENTS, true, false);
-            mVendorOverlayInstallObserver.startWatching();
             scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_TRUSTED_OVERLAY, 0);
 
             // Find base frameworks (resource packages without code).
-            mFrameworkInstallObserver = new AppDirObserver(
-                    frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
-            mFrameworkInstallObserver.startWatching();
             scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR
                     | PackageParser.PARSE_IS_PRIVILEGED,
@@ -1559,18 +1521,12 @@
 
             // Collected privileged system packages.
             File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
-            mPrivilegedInstallObserver = new AppDirObserver(
-                    privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);
-            mPrivilegedInstallObserver.startWatching();
             scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR
                     | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);
 
             // Collect ordinary system packages.
             File systemAppDir = new File(Environment.getRootDirectory(), "app");
-            mSystemInstallObserver = new AppDirObserver(
-                    systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
-            mSystemInstallObserver.startWatching();
             scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
 
@@ -1581,17 +1537,11 @@
             } catch (IOException e) {
                 // failed to look up canonical path, continue with original one
             }
-            mVendorInstallObserver = new AppDirObserver(
-                    vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
-            mVendorInstallObserver.startWatching();
             scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
 
             // Collect all OEM packages.
             File oemAppDir = new File(Environment.getOemDirectory(), "app");
-            mOemInstallObserver = new AppDirObserver(
-                    oemAppDir.getPath(), OBSERVER_EVENTS, true, false);
-            mOemInstallObserver.startWatching();
             scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
 
@@ -1665,14 +1615,8 @@
             if (!mOnlyCore) {
                 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                         SystemClock.uptimeMillis());
-                mAppInstallObserver = new AppDirObserver(
-                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false);
-                mAppInstallObserver.startWatching();
                 scanDirLI(mAppInstallDir, 0, scanMode, 0);
-    
-                mDrmAppInstallObserver = new AppDirObserver(
-                    mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false);
-                mDrmAppInstallObserver.startWatching();
+
                 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                         scanMode, 0);
 
@@ -1703,9 +1647,6 @@
                     }
                     reportSettingsProblem(Log.WARN, msg);
                 }
-            } else {
-                mAppInstallObserver = null;
-                mDrmAppInstallObserver = null;
             }
 
             // Now that we know all of the shared libraries, update all clients to have
@@ -4787,6 +4728,28 @@
         return allInstructionSets;
     }
 
+    @Override
+    public void forceDexOpt(String packageName) {
+        enforceSystemOrRoot("forceDexOpt");
+
+        PackageParser.Package pkg;
+        synchronized (mPackages) {
+            pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                throw new IllegalArgumentException("Missing package: " + packageName);
+            }
+        }
+
+        synchronized (mInstallLock) {
+            final String[] instructionSets = new String[] {
+                    getPrimaryInstructionSet(pkg.applicationInfo) };
+            final int res = performDexOptLI(pkg, instructionSets, true, false, true);
+            if (res != DEX_OPT_PERFORMED) {
+                throw new IllegalStateException("Failed to dexopt: " + res);
+            }
+        }
+    }
+
     private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets,
                                 boolean forceDex, boolean defer, boolean inclDependencies) {
         HashSet<String> done;
@@ -4898,16 +4861,6 @@
 
     private void updateSharedLibrariesLPw(PackageParser.Package pkg,
             PackageParser.Package changingLib) throws PackageManagerException {
-        // We might be upgrading from a version of the platform that did not
-        // provide per-package native library directories for system apps.
-        // Fix that up here.
-        if (isSystemApp(pkg)) {
-            PackageSetting ps = mSettings.mPackages.get(pkg.applicationInfo.packageName);
-            if (!isUpdatedSystemApp(pkg)) {
-                setBundledAppAbisAndRoots(pkg, ps);
-            }
-        }
-
         if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
             final ArraySet<String> usesLibraryFiles = new ArraySet<>();
             int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
@@ -5295,6 +5248,7 @@
             // The system package is special.
             dataPath = new File (Environment.getDataDirectory(), "system");
             pkg.applicationInfo.dataDir = dataPath.getPath();
+
         } else {
             // This is a normal package, need to make its data directory.
             dataPath = getDataPathForPackage(pkg.packageName, 0);
@@ -5429,6 +5383,26 @@
             NativeLibraryHelper.removeNativeBinariesFromDirLI(
                     new File(codePath, LIB_DIR_NAME), false /* delete dirs */);
             setBundledAppAbisAndRoots(pkg, pkgSetting);
+
+            // If we haven't found any native libraries for the app, check if it has
+            // renderscript code. We'll need to force the app to 32 bit if it has
+            // renderscript bitcode.
+            if (pkg.applicationInfo.primaryCpuAbi == null
+                    && pkg.applicationInfo.secondaryCpuAbi == null
+                    && Build.SUPPORTED_64_BIT_ABIS.length >  0) {
+                NativeLibraryHelper.Handle handle = null;
+                try {
+                    handle = NativeLibraryHelper.Handle.create(scanFile);
+                    if (NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+                        pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+                    }
+                } catch (IOException ioe) {
+                    Slog.w(TAG, "Error scanning system app : " + ioe);
+                } finally {
+                    IoUtils.closeQuietly(handle);
+                }
+            }
+
             setNativeLibraryPaths(pkg);
         } else {
             // TODO: We can probably be smarter about this stuff. For installed apps,
@@ -5563,11 +5537,20 @@
                     }
                 }
             }
-
-            pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
-            pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
         }
 
+        // This is a special case for the "system" package, where the ABI is
+        // dictated by the zygote configuration (and init.rc). We should keep track
+        // of this ABI so that we can deal with "normal" applications that run under
+        // the same UID correctly.
+        if (mPlatformPackage == pkg) {
+            pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
+                    Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
+        }
+
+        pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
+        pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+
         Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.applicationInfo.packageName
                 + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
                 + pkg.applicationInfo.nativeLibraryRootRequiresIsa);
@@ -7723,131 +7706,6 @@
             }
         }
     }
-    
-    private final class AppDirObserver extends FileObserver {
-        public AppDirObserver(String path, int mask, boolean isrom, boolean isPrivileged) {
-            super(path, mask);
-            mRootDir = path;
-            mIsRom = isrom;
-            mIsPrivileged = isPrivileged;
-        }
-
-        public void onEvent(int event, String path) {
-            String removedPackage = null;
-            int removedAppId = -1;
-            int[] removedUsers = null;
-            String addedPackage = null;
-            int addedAppId = -1;
-            int[] addedUsers = null;
-
-            // TODO post a message to the handler to obtain serial ordering
-            synchronized (mInstallLock) {
-                String fullPathStr = null;
-                File fullPath = null;
-                if (path != null) {
-                    fullPath = new File(mRootDir, path);
-                    fullPathStr = fullPath.getPath();
-                }
-
-                if (DEBUG_APP_DIR_OBSERVER)
-                    Log.v(TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event));
-
-                if (!isApkFile(fullPath)) {
-                    if (DEBUG_APP_DIR_OBSERVER)
-                        Log.v(TAG, "Ignoring change of non-package file: " + fullPathStr);
-                    return;
-                }
-
-                // Ignore packages that are being installed or
-                // have just been installed.
-                if (ignoreCodePath(fullPathStr)) {
-                    return;
-                }
-                PackageParser.Package p = null;
-                PackageSetting ps = null;
-                // reader
-                synchronized (mPackages) {
-                    p = mAppDirs.get(fullPathStr);
-                    if (p != null) {
-                        ps = mSettings.mPackages.get(p.applicationInfo.packageName);
-                        if (ps != null) {
-                            removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
-                        } else {
-                            removedUsers = sUserManager.getUserIds();
-                        }
-                    }
-                    addedUsers = sUserManager.getUserIds();
-                }
-                if ((event&REMOVE_EVENTS) != 0) {
-                    if (ps != null) {
-                        if (DEBUG_REMOVE) Slog.d(TAG, "Package disappeared: " + ps);
-                        removePackageLI(ps, true);
-                        removedPackage = ps.name;
-                        removedAppId = ps.appId;
-                    }
-                }
-
-                if ((event&ADD_EVENTS) != 0) {
-                    if (p == null) {
-                        if (DEBUG_INSTALL) Slog.d(TAG, "New file appeared: " + fullPath);
-                        int flags = PackageParser.PARSE_CHATTY | PackageParser.PARSE_MUST_BE_APK;
-                        if (mIsRom) {
-                            flags |= PackageParser.PARSE_IS_SYSTEM
-                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
-                            if (mIsPrivileged) {
-                                flags |= PackageParser.PARSE_IS_PRIVILEGED;
-                            }
-                        }
-                        try {
-                            p = scanPackageLI(fullPath, flags,
-                                    SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
-                                    System.currentTimeMillis(), UserHandle.ALL, null);
-                        } catch (PackageManagerException e) {
-                            Slog.w(TAG, "Failed to scan " + fullPath + ": " + e.getMessage());
-                            p = null;
-                        }
-                        if (p != null) {
-                            /*
-                             * TODO this seems dangerous as the package may have
-                             * changed since we last acquired the mPackages
-                             * lock.
-                             */
-                            // writer
-                            synchronized (mPackages) {
-                                updatePermissionsLPw(p.packageName, p,
-                                        p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0);
-                            }
-                            addedPackage = p.applicationInfo.packageName;
-                            addedAppId = UserHandle.getAppId(p.applicationInfo.uid);
-                        }
-                    }
-                }
-
-                // reader
-                synchronized (mPackages) {
-                    mSettings.writeLPr();
-                }
-            }
-
-            if (removedPackage != null) {
-                Bundle extras = new Bundle(1);
-                extras.putInt(Intent.EXTRA_UID, removedAppId);
-                extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null, removedUsers);
-            }
-            if (addedPackage != null) {
-                Bundle extras = new Bundle(1);
-                extras.putInt(Intent.EXTRA_UID, addedAppId);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
-                        extras, null, null, addedUsers);
-            }
-        }
-
-        private final String mRootDir;
-        private final boolean mIsRom;
-        private final boolean mIsPrivileged;
-    }
 
     @Override
     public void installPackage(String originPath, IPackageInstallObserver2 observer, int flags,
@@ -10969,7 +10827,6 @@
         // writer
         synchronized (mPackages) {
             PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);
-            setBundledAppAbisAndRoots(newPkg, ps);
             updatePermissionsLPw(newPkg.packageName, newPkg,
                     UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
             if (applyUserRestrictions) {
@@ -11778,22 +11635,25 @@
     }
 
     @Override
-    public void addCrossProfileIntentFilter(IntentFilter intentFilter, int sourceUserId,
-            int targetUserId, int flags) {
+    public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
+            int ownerUserId, int sourceUserId, int targetUserId, int flags) {
         mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        int callingUid = Binder.getCallingUid();
+        enforceOwnerRights(ownerPackage, ownerUserId, callingUid);
         if (intentFilter.countActions() == 0) {
             Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
             return;
         }
         synchronized (mPackages) {
             CrossProfileIntentFilter filter = new CrossProfileIntentFilter(intentFilter,
-                    targetUserId, flags);
+                    ownerPackage, UserHandle.getUserId(callingUid), targetUserId, flags);
             mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(filter);
             mSettings.writePackageRestrictionsLPr(sourceUserId);
         }
     }
 
+    @Override
     public void addCrossProfileIntentsForPackage(String packageName,
             int sourceUserId, int targetUserId) {
         mContext.enforceCallingOrSelfPermission(
@@ -11811,16 +11671,21 @@
     }
 
     @Override
-    public void clearCrossProfileIntentFilters(int sourceUserId) {
+    public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage,
+            int ownerUserId) {
         mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        int callingUid = Binder.getCallingUid();
+        enforceOwnerRights(ownerPackage, ownerUserId, callingUid);
+        int callingUserId = UserHandle.getUserId(callingUid);
         synchronized (mPackages) {
             CrossProfileIntentResolver resolver =
                     mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
             HashSet<CrossProfileIntentFilter> set =
                     new HashSet<CrossProfileIntentFilter>(resolver.filterSet());
             for (CrossProfileIntentFilter filter : set) {
-                if ((filter.getFlags() & PackageManager.SET_BY_PROFILE_OWNER) != 0) {
+                if (filter.getOwnerPackage().equals(ownerPackage)
+                        && filter.getOwnerUserId() == callingUserId) {
                     resolver.removeFilter(filter);
                 }
             }
@@ -11828,6 +11693,29 @@
         }
     }
 
+    // Enforcing that callingUid is owning pkg on userId
+    private void enforceOwnerRights(String pkg, int userId, int callingUid) {
+        // The system owns everything.
+        if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
+            return;
+        }
+        int callingUserId = UserHandle.getUserId(callingUid);
+        if (callingUserId != userId) {
+            throw new SecurityException("calling uid " + callingUid
+                    + " pretends to own " + pkg + " on user " + userId + " but belongs to user "
+                    + callingUserId);
+        }
+        PackageInfo pi = getPackageInfo(pkg, 0, callingUserId);
+        if (pi == null) {
+            throw new IllegalArgumentException("Unknown package " + pkg + " on user "
+                    + callingUserId);
+        }
+        if (!UserHandle.isSameApp(pi.applicationInfo.uid, callingUid)) {
+            throw new SecurityException("Calling uid " + callingUid
+                    + " does not own package " + pkg);
+        }
+    }
+
     @Override
     public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -11851,6 +11739,47 @@
                         preferred.activityInfo.name);
     }
 
+    /**
+     * Check if calling UID is the current home app. This handles both the case
+     * where the user has selected a specific home app, and where there is only
+     * one home app.
+     */
+    public boolean checkCallerIsHomeApp() {
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+
+        final int callingUid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getCallingUserId();
+        final List<ResolveInfo> allHomes = queryIntentActivities(intent, null, 0, callingUserId);
+        final ResolveInfo preferredHome = findPreferredActivity(intent, null, 0, allHomes, 0, true,
+                false, false, callingUserId);
+
+        if (preferredHome != null) {
+            if (callingUid == preferredHome.activityInfo.applicationInfo.uid) {
+                return true;
+            }
+        } else {
+            for (ResolveInfo info : allHomes) {
+                if (callingUid == info.activityInfo.applicationInfo.uid) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Enforce that calling UID is the current home app. This handles both the
+     * case where the user has selected a specific home app, and where there is
+     * only one home app.
+     */
+    public void enforceCallerIsHomeApp() {
+        if (!checkCallerIsHomeApp()) {
+            throw new SecurityException("Caller is not currently selected home app");
+        }
+    }
+
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index e272f38..2b4a24a 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -110,8 +110,9 @@
     // True if a user activity message should be sent.
     private boolean mUserActivityPending;
 
-    // True if the screen on blocker has been acquired.
-    private boolean mScreenOnBlockerAcquired;
+    // The currently active screen on listener. This field is non-null whenever the
+    // ScreenOnBlocker has been acquired and we are awaiting a callback to release it.
+    private ScreenOnUnblocker mPendingScreenOnUnblocker;
 
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
             IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
@@ -255,15 +256,16 @@
                 if (mActualPowerState != POWER_STATE_AWAKE) {
                     mActualPowerState = POWER_STATE_AWAKE;
                     mPendingWakeUpBroadcast = true;
-                    if (!mScreenOnBlockerAcquired) {
-                        mScreenOnBlockerAcquired = true;
+                    if (mPendingScreenOnUnblocker == null) {
                         mScreenOnBlocker.acquire();
                     }
+                    final ScreenOnUnblocker unblocker = new ScreenOnUnblocker();
+                    mPendingScreenOnUnblocker = unblocker;
                     mHandler.post(new Runnable() {
                         @Override
                         public void run() {
                             EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
-                            mPolicy.wakingUp(mScreenOnListener);
+                            mPolicy.wakingUp(unblocker);
                             mActivityManagerInternal.wakingUp();
                         }
                     });
@@ -459,18 +461,17 @@
         }
     }
 
-    private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
-            new WindowManagerPolicy.ScreenOnListener() {
+    private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
         @Override
         public void onScreenOn() {
             synchronized (mLock) {
-                if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
-                    mScreenOnBlockerAcquired = false;
+                if (mPendingScreenOnUnblocker == this) {
+                    mPendingScreenOnUnblocker = null;
                     mScreenOnBlocker.release();
                 }
             }
         }
-    };
+    }
 
     private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
         @Override
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index dc44e51..463f763 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -18,9 +18,7 @@
 
 import com.android.server.notification.NotificationDelegate;
 
-import android.os.IBinder;
-import android.service.notification.StatusBarNotification;
-
 public interface StatusBarManagerInternal {
     void setNotificationDelegate(NotificationDelegate delegate);
+    void buzzBeepBlinked();
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index e548fa5..d0013aa 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -111,6 +111,15 @@
         public void setNotificationDelegate(NotificationDelegate delegate) {
             mNotificationDelegate = delegate;
         }
+        @Override
+        public void buzzBeepBlinked() {
+            if (mBar != null) {
+                try {
+                    mBar.buzzBeepBlinked();
+                } catch (RemoteException ex) {
+                }
+            }
+        }
     };
 
     // ================================================================================
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index f18939f..51009af 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -24,6 +24,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
@@ -41,6 +42,13 @@
     private static final int MSG_GRANT_TRUST = 1;
     private static final int MSG_REVOKE_TRUST = 2;
     private static final int MSG_TRUST_TIMEOUT = 3;
+    private static final int MSG_RESTART_TIMEOUT = 4;
+
+    /**
+     * Time in uptime millis that we wait for the service connection, both when starting
+     * and when the service disconnects.
+     */
+    private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
 
     /**
      * Long extra for {@link #MSG_GRANT_TRUST}
@@ -53,6 +61,8 @@
     private final ComponentName mName;
 
     private ITrustAgentService mTrustAgentService;
+    private boolean mBound;
+    private long mScheduledRestartUptimeMillis;
 
     // Trust state
     private boolean mTrusted;
@@ -95,6 +105,10 @@
                     }
                     mTrustManagerService.updateTrust(mUserId);
                     break;
+                case MSG_RESTART_TIMEOUT:
+                    unbind();
+                    mTrustManagerService.resetAgent(mName, mUserId);
+                    break;
             }
         }
     };
@@ -123,6 +137,7 @@
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
+            mHandler.removeMessages(MSG_RESTART_TIMEOUT);
             mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
             mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
             setCallback(mCallback);
@@ -134,6 +149,9 @@
             mTrustAgentService = null;
             mTrustManagerService.mArchive.logAgentDied(mUserId, name);
             mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
+            if (mBound) {
+                scheduleRestart();
+            }
         }
     };
 
@@ -144,9 +162,12 @@
         mTrustManagerService = trustManagerService;
         mUserId = user.getIdentifier();
         mName = intent.getComponent();
-        if (!context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user)) {
-            if (DEBUG) Log.v(TAG, "can't bind to TrustAgent " + mName.flattenToShortString());
-            // TODO: retry somehow?
+        // Schedules a restart for when connecting times out. If the connection succeeds,
+        // the restart is canceled in mCallback's onConnected.
+        scheduleRestart();
+        mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
+        if (!mBound) {
+            Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
         }
     }
 
@@ -184,14 +205,38 @@
     }
 
     public void unbind() {
+        if (!mBound) {
+            return;
+        }
         if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
         mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
         mContext.unbindService(mConnection);
+        mBound = false;
         mTrustAgentService = null;
         mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
+        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
     }
 
     public boolean isConnected() {
         return mTrustAgentService != null;
     }
+
+    public boolean isBound() {
+        return mBound;
+    }
+
+    /**
+     * If not connected, returns the time at which the agent is restarted.
+     *
+     * @return restart time in uptime millis.
+     */
+    public long getScheduledRestartUptimeMillis() {
+        return mScheduledRestartUptimeMillis;
+    }
+
+    private void scheduleRestart() {
+        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
+        mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
+        mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
+    }
 }
diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java
index 56950d2..5e32d86 100644
--- a/services/core/java/com/android/server/trust/TrustArchive.java
+++ b/services/core/java/com/android/server/trust/TrustArchive.java
@@ -130,7 +130,7 @@
         }
     }
 
-    private static String formatDuration(long duration) {
+    public static String formatDuration(long duration) {
         StringBuilder sb = new StringBuilder();
         TimeUtils.formatDuration(duration, sb);
         return sb.toString();
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 1aec569..14436aa 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -45,6 +45,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.trust.TrustAgentService;
@@ -99,12 +100,6 @@
 
     private UserManager mUserManager;
 
-    /**
-     * Cache for {@link #refreshAgentList()}
-     */
-    private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>();
-
-
     public TrustManagerService(Context context) {
         super(context);
         mContext = context;
@@ -168,8 +163,8 @@
         List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
         LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
 
-        mObsoleteAgents.clear();
-        mObsoleteAgents.addAll(mActiveAgents);
+        ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>();
+        obsoleteAgents.addAll(mActiveAgents);
 
         for (UserInfo userInfo : userInfos) {
             int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
@@ -208,14 +203,14 @@
                             new Intent().setComponent(name), userInfo.getUserHandle());
                     mActiveAgents.add(agentInfo);
                 } else {
-                    mObsoleteAgents.remove(agentInfo);
+                    obsoleteAgents.remove(agentInfo);
                 }
             }
         }
 
         boolean trustMayHaveChanged = false;
-        for (int i = 0; i < mObsoleteAgents.size(); i++) {
-            AgentInfo info = mObsoleteAgents.valueAt(i);
+        for (int i = 0; i < obsoleteAgents.size(); i++) {
+            AgentInfo info = obsoleteAgents.valueAt(i);
             if (info.agent.isTrusted()) {
                 trustMayHaveChanged = true;
             }
@@ -228,6 +223,43 @@
         }
     }
 
+    private void removeAgentsOfPackage(String packageName) {
+        boolean trustMayHaveChanged = false;
+        for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (packageName.equals(info.component.getPackageName())) {
+                Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
+                if (info.agent.isTrusted()) {
+                    trustMayHaveChanged = true;
+                }
+                info.agent.unbind();
+                mActiveAgents.removeAt(i);
+            }
+        }
+        if (trustMayHaveChanged) {
+            updateTrustAll();
+        }
+    }
+
+    public void resetAgent(ComponentName name, int userId) {
+        boolean trustMayHaveChanged = false;
+        for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (name.equals(info.component) && userId == info.userId) {
+                Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
+                if (info.agent.isTrusted()) {
+                    trustMayHaveChanged = true;
+                }
+                info.agent.unbind();
+                mActiveAgents.removeAt(i);
+            }
+        }
+        if (trustMayHaveChanged) {
+            updateTrust(userId);
+        }
+        refreshAgentList();
+    }
+
     private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
         if (resolveInfo == null || resolveInfo.serviceInfo == null
                 || resolveInfo.serviceInfo.metaData == null) return null;
@@ -340,7 +372,7 @@
     private void removeListener(ITrustListener listener) {
         for (int i = 0; i < mTrustListeners.size(); i++) {
             if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
-                mTrustListeners.get(i);
+                mTrustListeners.remove(i);
                 return;
             }
         }
@@ -448,11 +480,18 @@
                 if (info.userId != user.id) { continue; }
                 boolean trusted = info.agent.isTrusted();
                 fout.print("    "); fout.println(info.component.flattenToShortString());
-                fout.print("     connected=" + dumpBool(info.agent.isConnected()));
+                fout.print("     bound=" + dumpBool(info.agent.isBound()));
+                fout.print(", connected=" + dumpBool(info.agent.isConnected()));
                 fout.println(", trusted=" + dumpBool(trusted));
                 if (trusted) {
                     fout.println("      message=\"" + info.agent.getMessage() + "\"");
                 }
+                if (!info.agent.isConnected()) {
+                    String restartTime = TrustArchive.formatDuration(
+                            info.agent.getScheduledRestartUptimeMillis()
+                                    - SystemClock.uptimeMillis());
+                    fout.println("      restartScheduledAt=" + restartTime);
+                }
                 if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) {
                     duplicateSimpleNames = true;
                 }
@@ -501,6 +540,11 @@
             // We're interested in all changes, even if just some components get enabled / disabled.
             return true;
         }
+
+        @Override
+        public void onPackageDisappeared(String packageName, int reason) {
+            removeAgentsOfPackage(packageName);
+        }
     };
 
     private class DevicePolicyReceiver extends BroadcastReceiver {
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index c011fd3..c6213f9 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -40,16 +40,17 @@
     public final static int ERROR_STALE_CONFIG = -2;
     public final static int ERROR_UNKNOWN = -3;
 
-    // Below should be in sync with hardware/libhardware/include/hardware/tv_input.h
     public static final int EVENT_DEVICE_AVAILABLE = 1;
     public static final int EVENT_DEVICE_UNAVAILABLE = 2;
     public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 3;
+    public static final int EVENT_FIRST_FRAME_CAPTURED = 4;
 
     public interface Callback {
         public void onDeviceAvailable(
                 TvInputHardwareInfo info, TvStreamConfig[] configs);
         public void onDeviceUnavailable(int deviceId);
         public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
+        public void onFirstFrameCaptured(int deviceId, int streamId);
     }
 
     private native long nativeOpen();
@@ -131,6 +132,11 @@
         mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
     }
 
+    private void firstFrameCapturedFromNative(int deviceId, int streamId) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId));
+    }
+
     // Handler.Callback implementation
 
     private Queue<Message> mPendingMessageQueue = new LinkedList<Message>();
@@ -167,6 +173,13 @@
                 break;
             }
 
+            case EVENT_FIRST_FRAME_CAPTURED: {
+                int deviceId = msg.arg1;
+                int streamId = msg.arg2;
+                mCallback.onFirstFrameCaptured(deviceId, streamId);
+                break;
+            }
+
             default:
                 Slog.e(TAG, "Unknown event: " + msg);
                 return false;
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index ea19012..65e617b 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -86,7 +86,6 @@
             new HdmiHotplugEventListener();
     private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener();
     private final IHdmiInputChangeListener mHdmiInputChangeListener = new HdmiInputChangeListener();
-    private final Set<Integer> mActiveHdmiSources = new HashSet<Integer>();
     // TODO: Should handle INACTIVE case.
     private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
 
@@ -172,6 +171,23 @@
         }
     }
 
+    @Override
+    public void onFirstFrameCaptured(int deviceId, int streamId) {
+        synchronized (mLock) {
+            Connection connection = mConnections.get(deviceId);
+            if (connection == null) {
+                Slog.e(TAG, "FirstFrameCaptured: Cannot find a connection with "
+                        + deviceId);
+                return;
+            }
+            Runnable runnable = connection.getOnFirstFrameCapturedLocked();
+            if (runnable != null) {
+                runnable.run();
+                connection.setOnFirstFrameCapturedLocked(null);
+            }
+        }
+    }
+
     public List<TvInputHardwareInfo> getHardwareList() {
         synchronized (mLock) {
             return mInfoList;
@@ -337,6 +353,74 @@
         return null;
     }
 
+    private int findDeviceIdForInputIdLocked(String inputId) {
+        for (int i = 0; i < mConnections.size(); ++i) {
+            Connection connection = mConnections.get(i);
+            if (connection.getInfoLocked().getId().equals(inputId)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Get the list of TvStreamConfig which is buffered mode.
+     */
+    public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int callingUid,
+            int resolvedUserId) {
+        List<TvStreamConfig> configsList = new ArrayList<TvStreamConfig>();
+        synchronized (mLock) {
+            int deviceId = findDeviceIdForInputIdLocked(inputId);
+            if (deviceId < 0) {
+                Slog.e(TAG, "Invalid inputId : " + inputId);
+                return configsList;
+            }
+            Connection connection = mConnections.get(deviceId);
+            for (TvStreamConfig config : connection.getConfigsLocked()) {
+                if (config.getType() == TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) {
+                    configsList.add(config);
+                }
+            }
+        }
+        return configsList;
+    }
+
+    /**
+     * Take a snapshot of the given TV input into the provided Surface.
+     */
+    public boolean captureFrame(String inputId, Surface surface, final TvStreamConfig config,
+            int callingUid, int resolvedUserId) {
+        synchronized (mLock) {
+            int deviceId = findDeviceIdForInputIdLocked(inputId);
+            if (deviceId < 0) {
+                Slog.e(TAG, "Invalid inputId : " + inputId);
+                return false;
+            }
+            Connection connection = mConnections.get(deviceId);
+            final TvInputHardwareImpl hardwareImpl = connection.getHardwareImplLocked();
+            if (hardwareImpl != null) {
+                // Stop previous capture.
+                Runnable runnable = connection.getOnFirstFrameCapturedLocked();
+                if (runnable != null) {
+                    runnable.run();
+                    connection.setOnFirstFrameCapturedLocked(null);
+                }
+
+                boolean result = hardwareImpl.startCapture(surface, config);
+                if (result) {
+                    connection.setOnFirstFrameCapturedLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            hardwareImpl.stopCapture(config);
+                        }
+                    });
+                }
+                return result;
+            }
+        }
+        return false;
+    }
+
     private class Connection implements IBinder.DeathRecipient {
         private final TvInputHardwareInfo mHardwareInfo;
         private TvInputInfo mInfo;
@@ -345,6 +429,7 @@
         private TvStreamConfig[] mConfigs = null;
         private Integer mCallingUid = null;
         private Integer mResolvedUserId = null;
+        private Runnable mOnFirstFrameCaptured;
 
         public Connection(TvInputHardwareInfo hardwareInfo) {
             mHardwareInfo = hardwareInfo;
@@ -367,6 +452,7 @@
             mInfo = info;
             mCallingUid = callingUid;
             mResolvedUserId = resolvedUserId;
+            mOnFirstFrameCaptured = null;
 
             if (mHardware != null && mCallback != null) {
                 try {
@@ -393,6 +479,10 @@
             return mHardware;
         }
 
+        public TvInputHardwareImpl getHardwareImplLocked() {
+            return mHardware;
+        }
+
         public ITvInputHardwareCallback getCallbackLocked() {
             return mCallback;
         }
@@ -409,6 +499,14 @@
             return mResolvedUserId;
         }
 
+        public void setOnFirstFrameCapturedLocked(Runnable runnable) {
+            mOnFirstFrameCaptured = runnable;
+        }
+
+        public Runnable getOnFirstFrameCapturedLocked() {
+            return mOnFirstFrameCaptured;
+        }
+
         @Override
         public void binderDied() {
             synchronized (mLock) {
@@ -486,19 +584,6 @@
                 if (surface == null && mActiveConfig == null) {
                     return false;
                 }
-                if (mInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) {
-                    if (surface != null) {
-                        // Set "Active Source" for HDMI.
-                        // TODO(hdmi): mHdmiClient.deviceSelect(...);
-                        mActiveHdmiSources.add(mInfo.getDeviceId());
-                    } else {
-                        mActiveHdmiSources.remove(mInfo.getDeviceId());
-                        if (mActiveHdmiSources.size() == 0) {
-                            // Tell HDMI that no HDMI source is active
-                            // TODO(hdmi): mHdmiClient.portSelect(null);
-                        }
-                    }
-                }
                 if (mAudioSource != null && mAudioSink != null) {
                     if (surface != null) {
                         AudioPortConfig sourceConfig = mAudioSource.activeConfig();
@@ -559,6 +644,37 @@
             // TODO(hdmi): mHdmiClient.sendKeyEvent(event);
             return false;
         }
+
+        private boolean startCapture(Surface surface, TvStreamConfig config) {
+            synchronized (mImplLock) {
+                if (mReleased) {
+                    return false;
+                }
+                if (surface == null || config == null) {
+                    return false;
+                }
+                if (config.getType() != TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) {
+                    return false;
+                }
+
+                int result = mHal.addStream(mInfo.getDeviceId(), surface, config);
+                return result == TvInputHal.SUCCESS;
+            }
+        }
+
+        private boolean stopCapture(TvStreamConfig config) {
+            synchronized (mImplLock) {
+                if (mReleased) {
+                    return false;
+                }
+                if (config == null) {
+                    return false;
+                }
+
+                int result = mHal.removeStream(mInfo.getDeviceId(), config);
+                return result == TvInputHal.SUCCESS;
+            }
+        }
     }
 
     interface Listener {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index d7ecd7a..1a9a85c 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -51,6 +51,7 @@
 import android.media.tv.TvInputHardwareInfo;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputService;
+import android.media.tv.TvStreamConfig;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
 import android.os.Binder;
@@ -204,9 +205,9 @@
         }, UserHandle.ALL, intentFilter, null, null);
     }
 
-    private static boolean hasHardwarePermission(PackageManager pm, ComponentName name) {
+    private static boolean hasHardwarePermission(PackageManager pm, ComponentName component) {
         return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
-                name.getPackageName()) == PackageManager.PERMISSION_GRANTED;
+                component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
     }
 
     private void buildTvInputListLocked(int userId) {
@@ -230,15 +231,15 @@
             }
             try {
                 inputList.clear();
-                ComponentName service = new ComponentName(si.packageName, si.name);
-                if (hasHardwarePermission(pm, service)) {
-                    ServiceState serviceState = userState.serviceStateMap.get(service);
+                ComponentName component = new ComponentName(si.packageName, si.name);
+                if (hasHardwarePermission(pm, component)) {
+                    ServiceState serviceState = userState.serviceStateMap.get(component);
                     if (serviceState == null) {
                         // We see this hardware TV input service for the first time; we need to
                         // prepare the ServiceState object so that we can connect to the service and
                         // let it add TvInputInfo objects to mInputList if there's any.
-                        serviceState = new ServiceState(service, userId);
-                        userState.serviceStateMap.put(service, serviceState);
+                        serviceState = new ServiceState(component, userId);
+                        userState.serviceStateMap.put(component, serviceState);
                     } else {
                         inputList.addAll(serviceState.mInputList);
                     }
@@ -257,7 +258,7 @@
                 }
 
                 // Reconnect the service if existing input is updated.
-                updateServiceConnectionLocked(service, userId);
+                updateServiceConnectionLocked(component, userId);
 
                 userState.packageSet.add(si.packageName);
             } catch (IOException | XmlPullParserException e) {
@@ -345,11 +346,11 @@
         return userState;
     }
 
-    private ServiceState getServiceStateLocked(ComponentName name, int userId) {
+    private ServiceState getServiceStateLocked(ComponentName component, int userId) {
         UserState userState = getUserStateLocked(userId);
-        ServiceState serviceState = userState.serviceStateMap.get(name);
+        ServiceState serviceState = userState.serviceStateMap.get(component);
         if (serviceState == null) {
-            throw new IllegalStateException("Service state not found for " + name + " (userId="
+            throw new IllegalStateException("Service state not found for " + component + " (userId="
                     + userId + ")");
         }
         return serviceState;
@@ -370,10 +371,14 @@
     }
 
     private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
-        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+        return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
+    }
+
+    private ITvInputSession getSessionLocked(SessionState sessionState) {
         ITvInputSession session = sessionState.mSession;
         if (session == null) {
-            throw new IllegalStateException("Session not yet created for token " + sessionToken);
+            throw new IllegalStateException("Session not yet created for token "
+                    + sessionState.mSessionToken);
         }
         return session;
     }
@@ -391,9 +396,9 @@
         // TODO: Find a way to maintain connection only when necessary.
     }
 
-    private void updateServiceConnectionLocked(ComponentName service, int userId) {
+    private void updateServiceConnectionLocked(ComponentName component, int userId) {
         UserState userState = getUserStateLocked(userId);
-        ServiceState serviceState = userState.serviceStateMap.get(service);
+        ServiceState serviceState = userState.serviceStateMap.get(component);
         if (serviceState == null) {
             return;
         }
@@ -414,10 +419,10 @@
                 return;
             }
             if (DEBUG) {
-                Slog.d(TAG, "bindServiceAsUser(service=" + service + ", userId=" + userId + ")");
+                Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
             }
 
-            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(service);
+            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
             // Binding service may fail if the service is updating.
             // In that case, the connection will be revived in buildTvInputListLocked called by
             // onSomePackagesChanged.
@@ -427,10 +432,10 @@
             // This means that the service is already connected but its state indicates that we have
             // nothing to do with it. Then, disconnect the service.
             if (DEBUG) {
-                Slog.d(TAG, "unbindService(service=" + service + ")");
+                Slog.d(TAG, "unbindService(service=" + component + ")");
             }
             mContext.unbindService(serviceState.mConnection);
-            userState.serviceStateMap.remove(service);
+            userState.serviceStateMap.remove(component);
         }
     }
 
@@ -652,8 +657,12 @@
     }
 
     private void removeSessionStateLocked(IBinder sessionToken, int userId) {
-        // Remove the session state from the global session state map of the current user.
         UserState userState = getUserStateLocked(userId);
+        if (sessionToken == userState.mainSessionToken) {
+            userState.mainSessionToken = null;
+        }
+
+        // Remove the session state from the global session state map of the current user.
         SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
 
         // Close the open log entry, if any.
@@ -684,45 +693,6 @@
         updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId);
     }
 
-    private void unregisterClientInternalLocked(IBinder clientToken, String inputId,
-            int userId) {
-        UserState userState = getUserStateLocked(userId);
-        ClientState clientState = userState.clientStateMap.get(clientToken);
-        if (clientState != null) {
-            clientState.mInputIds.remove(inputId);
-            if (clientState.isEmpty()) {
-                userState.clientStateMap.remove(clientToken);
-            }
-        }
-
-        TvInputInfo info = userState.inputMap.get(inputId).mInfo;
-        if (info == null) {
-            return;
-        }
-        ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
-        if (serviceState == null) {
-            return;
-        }
-
-        // Remove this client from the client list and unregister the callback.
-        serviceState.mClientTokens.remove(clientToken);
-        if (!serviceState.mClientTokens.isEmpty()) {
-            // We have other clients who want to keep the callback. Do this later.
-            return;
-        }
-        if (serviceState.mService == null || serviceState.mCallback == null) {
-            return;
-        }
-        try {
-            serviceState.mService.unregisterCallback(serviceState.mCallback);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "error in unregisterCallback", e);
-        } finally {
-            serviceState.mCallback = null;
-            updateServiceConnectionLocked(info.getComponent(), userId);
-        }
-    }
-
     private void notifyInputAddedLocked(UserState userState, String inputId) {
         if (DEBUG) {
             Slog.d(TAG, "notifyInputAdded: inputId = " + inputId);
@@ -775,7 +745,7 @@
     private void setStateLocked(String inputId, int state, int userId) {
         UserState userState = getUserStateLocked(userId);
         TvInputState inputState = userState.inputMap.get(inputId);
-        ServiceState serviceState = userState.serviceStateMap.get(inputId);
+        ServiceState serviceState = userState.serviceStateMap.get(inputState.mInfo.getComponent());
         int oldState = inputState.mState;
         inputState.mState = state;
         if (serviceState != null && serviceState.mService == null
@@ -919,6 +889,58 @@
         }
 
         @Override
+        public void setMainSession(IBinder sessionToken, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "setMainSession");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    UserState userState = getUserStateLocked(resolvedUserId);
+                    if (sessionToken == userState.mainSessionToken) {
+                        return;
+                    }
+
+                    SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                            resolvedUserId);
+                    ServiceState serviceState = getServiceStateLocked(
+                            sessionState.mInfo.getComponent(), resolvedUserId);
+                    ITvInputSession session = getSessionLocked(sessionState);
+
+                    ServiceState prevMainServiceState = null;
+                    ITvInputSession prevMainSession = null;
+                    if (userState.mainSessionToken != null) {
+                        SessionState prevMainSessionState = getSessionStateLocked(
+                                userState.mainSessionToken, Process.SYSTEM_UID, resolvedUserId);
+                        prevMainServiceState = getServiceStateLocked(
+                                prevMainSessionState.mInfo.getComponent(), resolvedUserId);
+                        prevMainSession = getSessionLocked(prevMainSessionState);
+                    }
+
+                    userState.mainSessionToken = sessionToken;
+
+                    // Inform the new main session first. See {@link TvInputService#onSetMain}.
+                    if (serviceState.mIsHardware) {
+                        try {
+                            session.setMainSession(true);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "error in setMainSession", e);
+                        }
+                    }
+                    if (prevMainSession != null && prevMainServiceState.mIsHardware) {
+                        try {
+                            prevMainSession.setMainSession(false);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "error in setMainSession", e);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void setSurface(IBinder sessionToken, Surface surface, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -1257,6 +1279,55 @@
         }
 
         @Override
+        public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int userId)
+                throws RemoteException {
+            if (mContext.checkCallingPermission(
+                    android.Manifest.permission.CAPTURE_TV_INPUT)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "getAvailableTvStreamConfigList");
+            try {
+                return mTvInputHardwareManager.getAvailableTvStreamConfigList(
+                        inputId, callingUid, resolvedUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config,
+                int userId)
+                throws RemoteException {
+            if (mContext.checkCallingPermission(
+                    android.Manifest.permission.CAPTURE_TV_INPUT)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "captureFrame");
+            try {
+                final String wrappedInputId;
+                synchronized (mLock) {
+                    UserState userState = getUserStateLocked(resolvedUserId);
+                    wrappedInputId = userState.wrappedInputMap.get(inputId);
+                }
+                return mTvInputHardwareManager.captureFrame(
+                        (wrappedInputId != null) ? wrappedInputId : inputId,
+                        surface, config, callingUid, resolvedUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         @SuppressWarnings("resource")
         protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
@@ -1305,13 +1376,6 @@
 
                         pw.increaseIndent();
 
-                        pw.println("mInputIds:");
-                        pw.increaseIndent();
-                        for (String inputId : client.mInputIds) {
-                            pw.println(inputId);
-                        }
-                        pw.decreaseIndent();
-
                         pw.println("mSessionTokens:");
                         pw.increaseIndent();
                         for (IBinder token : client.mSessionTokens) {
@@ -1426,10 +1490,15 @@
         // A set of callbacks.
         private final Set<ITvInputManagerCallback> callbackSet =
                 new HashSet<ITvInputManagerCallback>();
+
+        // A mapping from the TV input id to wrapped input id.
+        private final Map<String, String> wrappedInputMap = new HashMap<String, String>();
+
+        // The token of a "main" TV input session.
+        private IBinder mainSessionToken = null;
     }
 
     private final class ClientState implements IBinder.DeathRecipient {
-        private final List<String> mInputIds = new ArrayList<String>();
         private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
 
         private IBinder mClientToken;
@@ -1441,7 +1510,7 @@
         }
 
         public boolean isEmpty() {
-            return mInputIds.isEmpty() && mSessionTokens.isEmpty();
+            return mSessionTokens.isEmpty();
         }
 
         @Override
@@ -1449,17 +1518,13 @@
             synchronized (mLock) {
                 UserState userState = getUserStateLocked(mUserId);
                 // DO NOT remove the client state of clientStateMap in this method. It will be
-                // removed in releaseSessionLocked() or unregisterClientInternalLocked().
+                // removed in releaseSessionLocked().
                 ClientState clientState = userState.clientStateMap.get(mClientToken);
                 if (clientState != null) {
                     while (clientState.mSessionTokens.size() > 0) {
                         releaseSessionLocked(
                                 clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId);
                     }
-                    while (clientState.mInputIds.size() > 0) {
-                        unregisterClientInternalLocked(
-                                mClientToken, clientState.mInputIds.get(0), mUserId);
-                    }
                 }
                 mClientToken = null;
             }
@@ -1470,7 +1535,7 @@
         private final List<IBinder> mClientTokens = new ArrayList<IBinder>();
         private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
         private final ServiceConnection mConnection;
-        private final ComponentName mName;
+        private final ComponentName mComponent;
         private final boolean mIsHardware;
         private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>();
 
@@ -1479,10 +1544,10 @@
         private boolean mBound;
         private boolean mReconnecting;
 
-        private ServiceState(ComponentName name, int userId) {
-            mName = name;
-            mConnection = new InputServiceConnection(name, userId);
-            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mName);
+        private ServiceState(ComponentName component, int userId) {
+            mComponent = component;
+            mConnection = new InputServiceConnection(component, userId);
+            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mComponent);
         }
     }
 
@@ -1523,27 +1588,27 @@
     }
 
     private final class InputServiceConnection implements ServiceConnection {
-        private final ComponentName mName;
+        private final ComponentName mComponent;
         private final int mUserId;
 
-        private InputServiceConnection(ComponentName name, int userId) {
-            mName = name;
+        private InputServiceConnection(ComponentName component, int userId) {
+            mComponent = component;
             mUserId = userId;
         }
 
         @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
+        public void onServiceConnected(ComponentName component, IBinder service) {
             if (DEBUG) {
-                Slog.d(TAG, "onServiceConnected(name=" + name + ")");
+                Slog.d(TAG, "onServiceConnected(component=" + component + ")");
             }
             synchronized (mLock) {
                 UserState userState = getUserStateLocked(mUserId);
-                ServiceState serviceState = userState.serviceStateMap.get(mName);
+                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
                 serviceState.mService = ITvInputService.Stub.asInterface(service);
 
                 // Register a callback, if we need to.
                 if (serviceState.mIsHardware && serviceState.mCallback == null) {
-                    serviceState.mCallback = new ServiceCallback(mName, mUserId);
+                    serviceState.mCallback = new ServiceCallback(mComponent, mUserId);
                     try {
                         serviceState.mService.registerCallback(serviceState.mCallback);
                     } catch (RemoteException e) {
@@ -1557,7 +1622,7 @@
                 }
 
                 for (TvInputState inputState : userState.inputMap.values()) {
-                    if (inputState.mInfo.getComponent().equals(name)
+                    if (inputState.mInfo.getComponent().equals(component)
                             && inputState.mState != INPUT_STATE_DISCONNECTED) {
                         notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
                                 inputState.mState, null);
@@ -1589,17 +1654,17 @@
         }
 
         @Override
-        public void onServiceDisconnected(ComponentName name) {
+        public void onServiceDisconnected(ComponentName component) {
             if (DEBUG) {
-                Slog.d(TAG, "onServiceDisconnected(name=" + name + ")");
+                Slog.d(TAG, "onServiceDisconnected(component=" + component + ")");
             }
-            if (!mName.equals(name)) {
+            if (!mComponent.equals(component)) {
                 throw new IllegalArgumentException("Mismatched ComponentName: "
-                        + mName + " (expected), " + name + " (actual).");
+                        + mComponent + " (expected), " + component + " (actual).");
             }
             synchronized (mLock) {
                 UserState userState = getUserStateLocked(mUserId);
-                ServiceState serviceState = userState.serviceStateMap.get(mName);
+                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
                 if (serviceState != null) {
                     serviceState.mReconnecting = true;
                     serviceState.mBound = false;
@@ -1617,23 +1682,25 @@
                     }
 
                     for (TvInputState inputState : userState.inputMap.values()) {
-                        if (inputState.mInfo.getComponent().equals(name)) {
-                            notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
+                        if (inputState.mInfo.getComponent().equals(component)) {
+                            String inputId = inputState.mInfo.getId();
+                            notifyInputStateChangedLocked(userState, inputId,
                                     INPUT_STATE_DISCONNECTED, null);
+                            userState.wrappedInputMap.remove(inputId);
                         }
                     }
-                    updateServiceConnectionLocked(mName, mUserId);
+                    updateServiceConnectionLocked(mComponent, mUserId);
                 }
             }
         }
     }
 
     private final class ServiceCallback extends ITvInputServiceCallback.Stub {
-        private final ComponentName mName;
+        private final ComponentName mComponent;
         private final int mUserId;
 
-        ServiceCallback(ComponentName name, int userId) {
-            mName = name;
+        ServiceCallback(ComponentName component, int userId) {
+            mComponent = component;
             mUserId = userId;
         }
 
@@ -1645,13 +1712,13 @@
         }
 
         private void ensureValidInput(TvInputInfo inputInfo) {
-            if (inputInfo.getId() == null || !mName.equals(inputInfo.getComponent())) {
+            if (inputInfo.getId() == null || !mComponent.equals(inputInfo.getComponent())) {
                 throw new IllegalArgumentException("Invalid TvInputInfo");
             }
         }
 
         private void addTvInputLocked(TvInputInfo inputInfo) {
-            ServiceState serviceState = getServiceStateLocked(mName, mUserId);
+            ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
             serviceState.mInputList.add(inputInfo);
             buildTvInputListLocked(mUserId);
         }
@@ -1680,7 +1747,7 @@
         public void removeTvInput(String inputId) {
             ensureHardwarePermission();
             synchronized (mLock) {
-                ServiceState serviceState = getServiceStateLocked(mName, mUserId);
+                ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
                 boolean removed = false;
                 for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
                         it.hasNext(); ) {
@@ -1698,6 +1765,27 @@
                 }
             }
         }
+
+        @Override
+        public void setWrappedInputId(String inputId, String wrappedInputId) {
+            synchronized (mLock) {
+                if (!hasInputIdLocked(inputId)) {
+                    return;
+                }
+                UserState userState = getUserStateLocked(mUserId);
+                userState.wrappedInputMap.put(inputId, wrappedInputId);
+            }
+        }
+
+        private boolean hasInputIdLocked(String inputId) {
+            ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
+            for (TvInputInfo inputInfo : serviceState.mInputList) {
+                if (inputInfo.getId().equals(inputId)) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     private final class LogHandler extends Handler {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 874e105..9b69ce2 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -297,6 +297,13 @@
             mAppToken.mLaunchTaskBehind = false;
         } else {
             mAppToken.updateReportedVisibilityLocked();
+            if (mAppToken.mEnteringAnimation) {
+                mAppToken.mEnteringAnimation = false;
+                try {
+                    mService.mActivityManager.notifyEnterAnimationComplete(mAppToken.token);
+                } catch (RemoteException e) {
+                }
+            }
         }
 
         return false;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 312689b..3fcd067 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -110,6 +110,7 @@
     boolean mDeferRemoval;
 
     boolean mLaunchTaskBehind;
+    boolean mEnteringAnimation;
 
     AppWindowToken(WindowManagerService _service, IApplicationToken _token,
             boolean _voiceInteraction) {
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
new file mode 100644
index 0000000..64b852b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -0,0 +1,149 @@
+/*
+ * 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.wm;
+
+
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.Surface;
+import android.view.Surface.OutOfResourcesException;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+import android.util.Slog;
+
+class CircularDisplayMask {
+    private static final String TAG = "CircularDisplayMask";
+
+    private static final int STROKE_WIDTH = 2;
+    // size of the chin
+    private int mScreenOffset = 0;
+    // Display dimensions
+    private Point mScreenSize;
+
+    private final SurfaceControl mSurfaceControl;
+    private final Surface mSurface = new Surface();
+    private int mLastDW;
+    private int mLastDH;
+    private boolean mDrawNeeded;
+    private Paint mPaint;
+    private int mRotation;
+    private boolean mVisible;
+    private boolean mDimensionsUnequal = false;
+
+    public CircularDisplayMask(Display display, SurfaceSession session, int zOrder,
+            int screenOffset) {
+        mScreenSize = new Point();
+        display.getSize(mScreenSize);
+        if (mScreenSize.x != mScreenSize.y) {
+            Slog.w(TAG, "Screen dimensions of displayId = " + display.getDisplayId() +
+                    "are not equal, circularMask will not be drawn.");
+            mDimensionsUnequal = true;
+        }
+
+        SurfaceControl ctrl = null;
+        try {
+            ctrl = new SurfaceControl(session, "CircularDisplayMask",
+                mScreenSize.x, mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            ctrl.setLayerStack(display.getLayerStack());
+            ctrl.setLayer(zOrder);
+            ctrl.setPosition(0, 0);
+            ctrl.show();
+            mSurface.copyFrom(ctrl);
+        } catch (OutOfResourcesException e) {
+        }
+        mSurfaceControl = ctrl;
+        mDrawNeeded = true;
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setColor(Color.BLACK);
+        mPaint.setStrokeWidth(STROKE_WIDTH);
+        mScreenOffset = screenOffset;
+    }
+
+    private void drawIfNeeded() {
+        if (!mDrawNeeded || !mVisible || mDimensionsUnequal) {
+            return;
+        }
+        mDrawNeeded = false;
+
+        Rect dirty = new Rect(0, 0, mScreenSize.x, mScreenSize.y);
+        Canvas c = null;
+        try {
+            c = mSurface.lockCanvas(dirty);
+        } catch (IllegalArgumentException e) {
+        } catch (Surface.OutOfResourcesException e) {
+        }
+        if (c == null) {
+            return;
+        }
+        c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
+        switch (mRotation) {
+        case Surface.ROTATION_0:
+        case Surface.ROTATION_90:
+            // chin bottom or right
+            mSurfaceControl.setPosition(0, 0);
+            break;
+        case Surface.ROTATION_180:
+            // chin top
+            mSurfaceControl.setPosition(0, -mScreenOffset);
+            break;
+        case Surface.ROTATION_270:
+            // chin left
+            mSurfaceControl.setPosition(-mScreenOffset, 0);
+            break;
+        }
+
+        int circleRadius = mScreenSize.x / 2;
+        c.drawCircle(circleRadius, circleRadius, circleRadius, mPaint);
+        mSurface.unlockCanvasAndPost(c);
+    }
+
+    // Note: caller responsible for being inside
+    // Surface.openTransaction() / closeTransaction()
+    public void setVisibility(boolean on) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        mVisible = on;
+        drawIfNeeded();
+        if (on) {
+            mSurfaceControl.show();
+        } else {
+            mSurfaceControl.hide();
+        }
+    }
+
+    void positionSurface(int dw, int dh, int rotation) {
+        if (mLastDW == dw && mLastDH == dh && mRotation == rotation) {
+            return;
+        }
+        mLastDW = dw;
+        mLastDH = dh;
+        mDrawNeeded = true;
+        mRotation = rotation;
+        drawIfNeeded();
+    }
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eac2819..670ba55 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -440,6 +440,7 @@
     final SurfaceSession mFxSession;
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
+    CircularDisplayMask mCircularDisplayMask;
     FocusedStackFrame mFocusedStackFrame;
 
     int mFocusedStackLayer;
@@ -853,6 +854,8 @@
         } finally {
             SurfaceControl.closeTransaction();
         }
+
+        showCircularDisplayMaskIfNeeded();
     }
 
     public InputMonitor getInputMonitor() {
@@ -4447,6 +4450,7 @@
                 if (visible) {
                     mOpeningApps.add(wtoken);
                     wtoken.startingMoved = false;
+                    wtoken.mEnteringAnimation = true;
 
                     // If the token is currently hidden (should be the
                     // common case), then we need to set up to wait for
@@ -4469,6 +4473,7 @@
                     }
                 } else {
                     mClosingApps.add(wtoken);
+                    wtoken.mEnteringAnimation = false;
 
                     // If the token is currently visible (should be the
                     // common case), then set up to wait for it to be hidden.
@@ -5647,6 +5652,44 @@
         }
     }
 
+    public void showCircularDisplayMaskIfNeeded() {
+        // we're fullscreen and not hosted in an ActivityView
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_windowIsRound)
+                && mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_windowShowCircularMask)) {
+            mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
+        }
+    }
+
+    public void showCircularMask() {
+        synchronized(mWindowMap) {
+
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    ">>> OPEN TRANSACTION showDisplayMask");
+            SurfaceControl.openTransaction();
+            try {
+                // TODO(multi-display): support multiple displays
+                if (mCircularDisplayMask == null) {
+                    int screenOffset = (int) mContext.getResources().getDimensionPixelSize(
+                            com.android.internal.R.dimen.circular_display_mask_offset);
+
+                    mCircularDisplayMask = new CircularDisplayMask(
+                            getDefaultDisplayContentLocked().getDisplay(),
+                            mFxSession,
+                            mPolicy.windowTypeToLayerLw(
+                                    WindowManager.LayoutParams.TYPE_POINTER)
+                                    * TYPE_LAYER_MULTIPLIER + 10, screenOffset);
+                }
+                mCircularDisplayMask.setVisibility(true);
+            } finally {
+                SurfaceControl.closeTransaction();
+                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                        "<<< CLOSE TRANSACTION showDisplayMask");
+            }
+        }
+    }
+
     // TODO: more accounting of which pid(s) turned it on, keep count,
     // only allow disables from pids which have count on, etc.
     @Override
@@ -7252,6 +7295,8 @@
 
         public static final int UPDATE_SCRN_CAP = 35;
 
+        public static final int SHOW_DISPLAY_MASK = 36;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7646,6 +7691,11 @@
                     break;
                 }
 
+                case SHOW_DISPLAY_MASK: {
+                    showCircularMask();
+                    break;
+                }
+
                 case DO_ANIMATION_CALLBACK: {
                     try {
                         ((IRemoteCallback)msg.obj).sendResult(null);
@@ -9168,6 +9218,9 @@
             if (mStrictModeFlash != null) {
                 mStrictModeFlash.positionSurface(defaultDw, defaultDh);
             }
+            if (mCircularDisplayMask != null) {
+                mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation);
+            }
 
             boolean focusDisplayed = false;
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index f3afe82..3f07dd90 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -740,6 +740,7 @@
             mSurfaceX = 0;
             mSurfaceY = 0;
             w.mLastSystemDecorRect.set(0, 0, 0, 0);
+            mLastClipRect.set(0, 0, 0, 0);
 
             // Set up surface control with initial size.
             try {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 5599760..9a4d900 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -10,7 +10,6 @@
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
-    $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
     $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
     $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp
deleted file mode 100644
index a6d9297..0000000
--- a/services/core/jni/com_android_server_dreams_McuHal.cpp
+++ /dev/null
@@ -1,100 +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.
- */
-
-#define LOG_TAG "McuHal"
-
-//#define LOG_NDEBUG 0
-
-#include "JNIHelp.h"
-#include "jni.h"
-
-#include <ScopedUtfChars.h>
-#include <ScopedPrimitiveArray.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <hardware/mcu.h>
-
-namespace android {
-
-static jlong nativeOpen(JNIEnv* env, jclass clazz) {
-    mcu_module_t* module = NULL;
-    status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID,
-            (hw_module_t const**)&module);
-    if (err) {
-        ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
-        return 0;
-    }
-
-    err = module->init(module);
-    if (err) {
-        ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
-        return 0;
-    }
-
-    return reinterpret_cast<jlong>(module);
-}
-
-static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz,
-        jlong ptr, jstring msgStr, jbyteArray argArray) {
-    mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr);
-
-    ScopedUtfChars msg(env, msgStr);
-    ALOGV("Sending message %s to MCU", msg.c_str());
-
-    void* result = NULL;
-    size_t resultSize = 0;
-    status_t err;
-    if (argArray) {
-        ScopedByteArrayRO arg(env, argArray);
-        err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(),
-                &result, &resultSize);
-    } else {
-        err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize);
-    }
-    if (err) {
-        ALOGE("Couldn't send message to MCU (%s)", strerror(-err));
-        return NULL;
-    }
-
-    if (!result) {
-        return NULL;
-    }
-
-    jbyteArray resultArray = env->NewByteArray(resultSize);
-    if (resultArray) {
-        env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result));
-    }
-    free(result);
-    return resultArray;
-}
-
-static JNINativeMethod gMcuHalMethods[] = {
-    /* name, signature, funcPtr */
-    { "nativeOpen", "()J",
-            (void*) nativeOpen },
-    { "nativeSendMessage", "(JLjava/lang/String;[B)[B",
-            (void*) nativeSendMessage },
-};
-
-int register_android_server_dreams_McuHal(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal",
-            gMcuHalMethods, NELEM(gMcuHalMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
-    return 0;
-}
-
-} /* namespace android */
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index 47f83d0..5c557b6 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -18,8 +18,8 @@
 
 #define LOG_NDEBUG 1
 
-#include "JNIHelp.h"
-#include "ScopedPrimitiveArray.h"
+#include <JNIHelp.h>
+#include <ScopedPrimitiveArray.h>
 
 #include <cstring>
 
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 8bb6e8a..46327d7 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -53,6 +53,7 @@
 static jmethodID method_reportGeofencePauseStatus;
 static jmethodID method_reportGeofenceResumeStatus;
 static jmethodID method_reportMeasurementData;
+static jmethodID method_reportNavigationMessages;
 
 static const GpsInterface* sGpsInterface = NULL;
 static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -62,6 +63,7 @@
 static const AGpsRilInterface* sAGpsRilInterface = NULL;
 static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
 static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
+static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
 
 // temporary storage for GPS callbacks
 static GpsSvStatus  sGpsSvStatus;
@@ -447,6 +449,10 @@
             clazz,
             "reportMeasurementData",
             "(Landroid/location/GpsMeasurementsEvent;)V");
+    method_reportNavigationMessages = env->GetMethodID(
+            clazz,
+            "reportNavigationMessage",
+            "(Landroid/location/GpsNavigationMessageEvent;)V");
 
     err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
     if (err == 0) {
@@ -472,6 +478,9 @@
             (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
         sGpsMeasurementInterface =
             (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
+        sGpsNavigationMessageInterface =
+            (const GpsNavigationMessageInterface*)sGpsInterface->get_extension(
+                    GPS_NAVIGATION_MESSAGE_INTERFACE);
     }
 }
 
@@ -1212,7 +1221,6 @@
         checkAndClearExceptionFromCallback(env, __FUNCTION__);
     } else {
         ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size);
-        return;
     }
 }
 
@@ -1223,7 +1231,7 @@
 
 static jboolean android_location_GpsLocationProvider_is_measurement_supported(
         JNIEnv* env,
-        jobject obj) {
+        jclass clazz) {
     if (sGpsMeasurementInterface != NULL) {
         return JNI_TRUE;
     }
@@ -1259,6 +1267,110 @@
     return JNI_TRUE;
 }
 
+static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
+    size_t dataLength = message->data_length;
+    uint8_t* data = message->data;
+    if (dataLength == 0 || data == NULL) {
+        ALOGE("Invalid Navigation Message found: data=%p, length=%d", data, dataLength);
+        return NULL;
+    }
+
+    jclass navigationMessageClass = env->FindClass("android/location/GpsNavigationMessage");
+    jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
+    jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
+
+    jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
+    env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
+
+    jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
+    env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
+
+    jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
+    env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
+
+    jmethodID setSubmessageIdMethod =
+            env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
+    env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
+
+    jbyteArray dataArray = env->NewByteArray(dataLength);
+    env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
+    jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
+    env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
+
+    return navigationMessageObject;
+}
+
+static void navigation_message_callback(GpsNavigationMessage* message) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (message == NULL) {
+        ALOGE("Invalid Navigation Message provided to callback");
+        return;
+    }
+
+    if (message->size == sizeof(GpsNavigationMessage)) {
+        jobject navigationMessage = translate_gps_navigation_message(env, message);
+
+        jclass navigationMessageEventClass =
+                env->FindClass("android/location/GpsNavigationMessageEvent");
+        jmethodID navigationMessageEventCtor = env->GetMethodID(
+                navigationMessageEventClass,
+                "<init>",
+                "(Landroid/location/GpsNavigationMessage;)V");
+        jobject navigationMessageEvent = env->NewObject(
+                navigationMessageEventClass,
+                navigationMessageEventCtor,
+                navigationMessage);
+
+        env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
+        checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    } else {
+        ALOGE("Invalid GpsNavigationMessage size found: %d", message->size);
+    }
+}
+
+GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
+    sizeof(GpsNavigationMessageCallbacks),
+    navigation_message_callback,
+};
+
+static jboolean android_location_GpsLocationProvider_is_navigation_message_supported(
+        JNIEnv* env,
+        jclass clazz) {
+    if(sGpsNavigationMessageInterface != NULL) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_start_navigation_message_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsNavigationMessageInterface == NULL) {
+        ALOGE("Navigation Message interface is not available.");
+        return JNI_FALSE;
+    }
+
+    int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
+    if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
+        ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsNavigationMessageInterface == NULL) {
+        ALOGE("Navigation Message interface is not available.");
+        return JNI_FALSE;
+    }
+
+    sGpsNavigationMessageInterface->close();
+    return JNI_TRUE;
+}
+
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -1336,7 +1448,16 @@
             (void*) android_location_GpsLocationProvider_start_measurement_collection},
     {"native_stop_measurement_collection",
             "()Z",
-            (void*) android_location_GpsLocationProvider_stop_measurement_collection}
+            (void*) android_location_GpsLocationProvider_stop_measurement_collection},
+    {"native_is_navigation_message_supported",
+            "()Z",
+            (void*) android_location_GpsLocationProvider_is_navigation_message_supported},
+    {"native_start_navigation_message_collection",
+            "()Z",
+            (void*) android_location_GpsLocationProvider_start_navigation_message_collection},
+    {"native_stop_navigation_message_collection",
+            "()Z",
+            (void*) android_location_GpsLocationProvider_stop_navigation_message_collection},
 };
 
 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index a9d5c72..41976ff 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -36,6 +36,7 @@
     jmethodID deviceAvailable;
     jmethodID deviceUnavailable;
     jmethodID streamConfigsChanged;
+    jmethodID firstFrameCaptured;
 } gTvInputHalClassInfo;
 
 static struct {
@@ -539,6 +540,14 @@
         thread = connection.mThread;
     }
     thread->onCaptured(seq, succeeded);
+    if (seq == 0) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->CallVoidMethod(
+                mThiz,
+                gTvInputHalClassInfo.firstFrameCaptured,
+                deviceId,
+                streamId);
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -638,6 +647,9 @@
     GET_METHOD_ID(
             gTvInputHalClassInfo.streamConfigsChanged, clazz,
             "streamConfigsChangedFromNative", "(I)V");
+    GET_METHOD_ID(
+            gTvInputHalClassInfo.firstFrameCaptured, clazz,
+            "firstFrameCapturedFromNative", "(II)V");
 
     FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/media/tv/TvStreamConfig");
     gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz));
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bf7501e..ce2ca9b 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -37,7 +37,6 @@
 int register_android_server_location_GpsLocationProvider(JNIEnv* env);
 int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
-int register_android_server_dreams_McuHal(JNIEnv* env);
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
 int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
 int register_android_server_tv_TvInputHal(JNIEnv* env);
@@ -73,7 +72,6 @@
     register_android_server_connectivity_Vpn(env);
     register_android_server_AssetAtlasService(env);
     register_android_server_ConsumerIrService(env);
-    register_android_server_dreams_McuHal(env);
     register_android_server_BatteryStatsService(env);
     register_android_server_hdmi_HdmiCecController(env);
     register_android_server_hdmi_HdmiMhlController(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e0612eb..25f9e9b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -252,8 +252,6 @@
         }
     };
 
-    private IAppOpsService mAppOpsService;
-
     static class ActiveAdmin {
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
@@ -1288,24 +1286,6 @@
         getUserData(UserHandle.USER_OWNER);
         loadDeviceOwner();
         cleanUpOldUsers();
-        mAppOpsService = IAppOpsService.Stub.asInterface(
-                ServiceManager.getService(Context.APP_OPS_SERVICE));
-        if (mDeviceOwner != null) {
-            if (mDeviceOwner.hasDeviceOwner()) {
-                try {
-                    mAppOpsService.setDeviceOwner(mDeviceOwner.getDeviceOwnerPackageName());
-                } catch (RemoteException e) {
-                    Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
-                }
-            }
-            for (Integer i : mDeviceOwner.getProfileOwnerKeys()) {
-                try {
-                    mAppOpsService.setProfileOwner(mDeviceOwner.getProfileOwnerPackageName(i), i);
-                } catch (RemoteException e) {
-                    Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
-                }
-            }
-        }
         // Register an observer for watching for user setup complete.
         new SetupContentObserver(mHandler).register(mContext.getContentResolver());
         // Initialize the user setup state, to handle the upgrade case.
@@ -3169,14 +3149,6 @@
                         "Trying to set device owner but device owner is already set.");
             }
 
-            long token = Binder.clearCallingIdentity();
-            try {
-                mAppOpsService.setDeviceOwner(packageName);
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
             if (mDeviceOwner == null) {
                 // Device owner is not set and does not exist, set it.
                 mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
@@ -3284,14 +3256,7 @@
                 throw new IllegalStateException(
                         "Trying to set profile owner but user is already set-up.");
             }
-            long token = Binder.clearCallingIdentity();
-            try {
-                mAppOpsService.setProfileOwner(packageName, userHandle);
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+
             if (mDeviceOwner == null) {
                 // Device owner state does not exist, create it.
                 mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
@@ -3606,12 +3571,12 @@
             long id = Binder.clearCallingIdentity();
             try {
                 if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) {
-                    pm.addCrossProfileIntentFilter(filter, callingUserId, UserHandle.USER_OWNER,
-                            PackageManager.SET_BY_PROFILE_OWNER);
+                    pm.addCrossProfileIntentFilter(filter, who.getPackageName(),
+                            mContext.getUserId(), callingUserId, UserHandle.USER_OWNER, 0);
                 }
                 if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) {
-                    pm.addCrossProfileIntentFilter(filter, UserHandle.USER_OWNER, callingUserId,
-                            PackageManager.SET_BY_PROFILE_OWNER);
+                    pm.addCrossProfileIntentFilter(filter, who.getPackageName(),
+                            mContext.getUserId(), UserHandle.USER_OWNER, callingUserId, 0);
                 }
             } catch (RemoteException re) {
                 // Shouldn't happen
@@ -3631,10 +3596,12 @@
             IPackageManager pm = AppGlobals.getPackageManager();
             long id = Binder.clearCallingIdentity();
             try {
-                pm.clearCrossProfileIntentFilters(callingUserId);
+                pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName(),
+                        callingUserId);
                 // If we want to support multiple managed profiles, we will have to only remove
                 // those that have callingUserId as their target.
-                pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER);
+                pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER, who.getPackageName(),
+                        callingUserId);
             } catch (RemoteException re) {
                 // Shouldn't happen
             } finally {
@@ -4291,9 +4258,11 @@
             if (Settings.Secure.getIntForUser(resolver, Settings.Secure.USER_SETUP_COMPLETE, 0,
                     userHandle) != 0) {
                 DevicePolicyData policy = getUserData(userHandle);
-                policy.mUserSetupComplete = true;
-                synchronized (this) {
-                    saveSettingsLocked(userHandle);
+                if (!policy.mUserSetupComplete) {
+                    policy.mUserSetupComplete = true;
+                    synchronized (this) {
+                        saveSettingsLocked(userHandle);
+                    }
                 }
             }
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bf2edc8..70266ee 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -352,6 +352,9 @@
         mFirstBoot = mPackageManagerService.isFirstBoot();
         mPackageManager = mSystemContext.getPackageManager();
 
+        Slog.i(TAG, "User Service");
+        ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
+
         // Initialize attribute cache used to cache resources from packages.
         AttributeCache.init(mSystemContext);
 
@@ -434,10 +437,6 @@
             Slog.i(TAG, "Entropy Mixer");
             ServiceManager.addService("entropy", new EntropyMixer(context));
 
-            Slog.i(TAG, "User Service");
-            ServiceManager.addService(Context.USER_SERVICE,
-                    UserManagerService.getInstance());
-
             mContentResolver = context.getContentResolver();
 
             // The AccountManager must come before the ContentService
@@ -674,6 +673,8 @@
                 mSystemServiceManager.startService(
                             "com.android.server.wifi.WifiScanningService");
 
+                mSystemServiceManager.startService("com.android.server.wifi.RttService");
+
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET)) {
                     mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
                 }
@@ -930,7 +931,9 @@
                 mSystemServiceManager.startService(HdmiControlService.class);
             }
 
-            mSystemServiceManager.startService(TvInputManagerService.class);
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+                mSystemServiceManager.startService(TvInputManagerService.class);
+            }
 
             if (!disableNonCoreServices) {
                 try {
diff --git a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
similarity index 64%
rename from services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
rename to services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index cb8da70..2b693a3 100644
--- a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -1,4 +1,4 @@
-package com.android.server.task;
+package com.android.server.job;
 
 
 import android.content.ComponentName;
@@ -9,40 +9,32 @@
 import android.test.AndroidTestCase;
 import android.test.RenamingDelegatingContext;
 import android.util.Log;
+import android.util.ArraySet;
 
-import com.android.server.job.JobMapReadFinishedListener;
-import com.android.server.job.JobStore;
 import com.android.server.job.controllers.JobStatus;
 
-import java.util.List;
+import java.util.Iterator;
 
 /**
  * Test reading and writing correctly from file.
  */
-public class TaskStoreTest extends AndroidTestCase {
+public class JobStoreTest extends AndroidTestCase {
     private static final String TAG = "TaskStoreTest";
     private static final String TEST_PREFIX = "_test_";
-    // private static final int USER_NON_0 = 3;
+
     private static final int SOME_UID = 34234;
     private ComponentName mComponent;
-    private static final long IO_WAIT = 600L;
+    private static final long IO_WAIT = 1000L;
 
     JobStore mTaskStoreUnderTest;
     Context mTestContext;
-    JobMapReadFinishedListener mTaskMapReadFinishedListenerStub =
-            new JobMapReadFinishedListener() {
-        @Override
-        public void onJobMapReadFinished(List<JobStatus> tasks) {
-            // do nothing.
-        }
-    };
 
     @Override
     public void setUp() throws Exception {
         mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
         Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'");
-        mTaskStoreUnderTest = JobStore.initAndGetForTesting(mTestContext,
-                mTestContext.getFilesDir(), mTaskMapReadFinishedListenerStub);
+        mTaskStoreUnderTest =
+                JobStore.initAndGetForTesting(mTestContext, mTestContext.getFilesDir());
         mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
     }
 
@@ -69,19 +61,17 @@
         mTaskStoreUnderTest.add(ts);
         Thread.sleep(IO_WAIT);
         // Manually load tasks from xml file.
-        mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
-            @Override
-            public void onJobMapReadFinished(List<JobStatus> tasks) {
-                assertEquals("Didn't get expected number of persisted tasks.", 1, tasks.size());
-                JobStatus loadedTaskStatus = tasks.get(0);
-                assertTasksEqual(task, loadedTaskStatus.getJob());
-                assertEquals("Different uids.", SOME_UID, tasks.get(0).getUid());
-                compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
-                        ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
-                compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
-                        ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed());
-            }
-        });
+        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+
+        assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size());
+        final JobStatus loadedTaskStatus = jobStatusSet.iterator().next();
+        assertTasksEqual(task, loadedTaskStatus.getJob());
+        assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid());
+        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
+                ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
+        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
+                ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed());
 
     }
 
@@ -104,26 +94,25 @@
         mTaskStoreUnderTest.add(taskStatus1);
         mTaskStoreUnderTest.add(taskStatus2);
         Thread.sleep(IO_WAIT);
-        mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
-            @Override
-            public void onJobMapReadFinished(List<JobStatus> tasks) {
-                assertEquals("Incorrect # of persisted tasks.", 2, tasks.size());
-                JobStatus loaded1 = tasks.get(0);
-                JobStatus loaded2 = tasks.get(1);
-                assertTasksEqual(task1, loaded1.getJob());
-                assertTasksEqual(task2, loaded2.getJob());
 
-                // Check that the loaded task has the correct runtimes.
-                compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
-                        taskStatus1.getEarliestRunTime(), loaded1.getEarliestRunTime());
-                compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
-                        taskStatus1.getLatestRunTimeElapsed(), loaded1.getLatestRunTimeElapsed());
-                compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
-                        taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime());
-                compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
-                        taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed());
-            }
-        });
+        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+        assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size());
+        Iterator<JobStatus> it = jobStatusSet.iterator();
+        JobStatus loaded1 = it.next();
+        JobStatus loaded2 = it.next();
+        assertTasksEqual(task1, loaded1.getJob());
+        assertTasksEqual(task2, loaded2.getJob());
+
+        // Check that the loaded task has the correct runtimes.
+        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
+                taskStatus1.getEarliestRunTime(), loaded1.getEarliestRunTime());
+        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
+                taskStatus1.getLatestRunTimeElapsed(), loaded1.getLatestRunTimeElapsed());
+        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
+                taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime());
+        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
+                taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed());
 
     }
 
@@ -144,15 +133,12 @@
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
-        mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
-            @Override
-            public void onJobMapReadFinished(List<JobStatus> tasks) {
-                assertEquals("Incorrect # of persisted tasks.", 1, tasks.size());
-                JobStatus loaded = tasks.get(0);
-                assertTasksEqual(task, loaded.getJob());
-            }
-        });
 
+        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
+        JobStatus loaded = jobStatusSet.iterator().next();
+        assertTasksEqual(task, loaded.getJob());
     }
 
     /**
@@ -201,4 +187,4 @@
 
     private static class StubClass {}
 
-}
\ No newline at end of file
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 4018def..1c20d5d 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -19,52 +19,56 @@
 import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.usage.IUsageStatsManager;
-import android.app.usage.PackageUsageStats;
-import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.util.SparseArray;
+
 import com.android.internal.os.BackgroundThread;
 import com.android.server.SystemService;
 
 import java.io.File;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
+import java.util.Arrays;
+import java.util.List;
 
-public class UsageStatsService extends SystemService {
+public class UsageStatsService extends SystemService implements
+        UserUsageStatsService.StatsUpdatedListener {
     static final String TAG = "UsageStatsService";
 
     static final boolean DEBUG = false;
     private static final long TEN_SECONDS = 10 * 1000;
     private static final long TWENTY_MINUTES = 20 * 60 * 1000;
     private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES;
-    private static final int USAGE_STAT_RESULT_LIMIT = 10;
-    private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    static final int USAGE_STAT_RESULT_LIMIT = 10;
 
     // Handler message types.
     static final int MSG_REPORT_EVENT = 0;
     static final int MSG_FLUSH_TO_DISK = 1;
+    static final int MSG_REMOVE_USER = 2;
 
-    final Object mLock = new Object();
+    private final Object mLock = new Object();
     Handler mHandler;
     AppOpsManager mAppOps;
+    UserManager mUserManager;
 
-    private UsageStatsDatabase mDatabase;
-    private UsageStats[] mCurrentStats = new UsageStats[UsageStatsManager.BUCKET_COUNT];
-    private TimeSparseArray<UsageStats.Event> mCurrentEvents = new TimeSparseArray<>();
-    private boolean mStatsChanged = false;
-    private Calendar mDailyExpiryDate;
+    private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
+    private File mUsageStatsDir;
 
     public UsageStatsService(Context context) {
         super(context);
@@ -72,115 +76,96 @@
 
     @Override
     public void onStart() {
-        mDailyExpiryDate = Calendar.getInstance();
         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
         mHandler = new H(BackgroundThread.get().getLooper());
 
         File systemDataDir = new File(Environment.getDataDirectory(), "system");
-        mDatabase = new UsageStatsDatabase(new File(systemDataDir, "usagestats"));
-        mDatabase.init();
+        mUsageStatsDir = new File(systemDataDir, "usagestats");
+        mUsageStatsDir.mkdirs();
+        if (!mUsageStatsDir.exists()) {
+            throw new IllegalStateException("Usage stats directory does not exist: "
+                    + mUsageStatsDir.getAbsolutePath());
+        }
+
+        getContext().registerReceiver(new UserRemovedReceiver(),
+                new IntentFilter(Intent.ACTION_USER_REMOVED));
 
         synchronized (mLock) {
-            initLocked();
+            cleanUpRemovedUsersLocked();
         }
 
         publishLocalService(UsageStatsManagerInternal.class, new LocalService());
         publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
     }
 
-    private void initLocked() {
-        int nullCount = 0;
-        for (int i = 0; i < mCurrentStats.length; i++) {
-            mCurrentStats[i] = mDatabase.getLatestUsageStats(i);
-            if (mCurrentStats[i] == null) {
-                nullCount++;
-            }
-        }
+    private class UserRemovedReceiver extends BroadcastReceiver {
 
-        if (nullCount > 0) {
-            if (nullCount != mCurrentStats.length) {
-                // This is weird, but we shouldn't fail if something like this
-                // happens.
-                Slog.w(TAG, "Some stats have no latest available");
-            } else {
-                // This must be first boot.
-            }
-
-            // By calling loadActiveStatsLocked, we will
-            // generate new stats for each bucket.
-            loadActiveStatsLocked();
-        } else {
-            // Set up the expiry date to be one day from the latest daily stat.
-            // This may actually be today and we will rollover on the first event
-            // that is reported.
-            mDailyExpiryDate.setTimeInMillis(
-                    mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp);
-            mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1);
-            UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate);
-            Slog.i(TAG, "Rollover scheduled for " + sDateFormat.format(mDailyExpiryDate.getTime()));
-        }
-
-        // Now close off any events that were open at the time this was saved.
-        for (UsageStats stat : mCurrentStats) {
-            final int pkgCount = stat.getPackageCount();
-            for (int i = 0; i < pkgCount; i++) {
-                PackageUsageStats pkgStats = stat.getPackage(i);
-                if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND ||
-                        pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) {
-                    updateStatsLocked(stat, pkgStats.mPackageName, stat.mLastTimeSaved,
-                            UsageStats.Event.END_OF_DAY);
-                    notifyStatsChangedLocked();
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent != null && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                if (userId >= 0) {
+                    mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
                 }
             }
         }
     }
 
-    private void rolloverStatsLocked() {
-        final long startTime = System.currentTimeMillis();
-        Slog.i(TAG, "Rolling over usage stats");
-
-        // Finish any ongoing events with an END_OF_DAY event. Make a note of which components
-        // need a new CONTINUE_PREVIOUS_DAY entry.
-        ArraySet<String> continuePreviousDay = new ArraySet<>();
-        for (UsageStats stat : mCurrentStats) {
-            final int pkgCount = stat.getPackageCount();
-            for (int i = 0; i < pkgCount; i++) {
-                PackageUsageStats pkgStats = stat.getPackage(i);
-                if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND ||
-                        pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) {
-                    continuePreviousDay.add(pkgStats.mPackageName);
-                    updateStatsLocked(stat, pkgStats.mPackageName,
-                            mDailyExpiryDate.getTimeInMillis() - 1, UsageStats.Event.END_OF_DAY);
-                    mStatsChanged = true;
-                }
-            }
-        }
-
-        persistActiveStatsLocked();
-        mDatabase.prune();
-        loadActiveStatsLocked();
-
-        final int continueCount = continuePreviousDay.size();
-        for (int i = 0; i < continueCount; i++) {
-            String name = continuePreviousDay.valueAt(i);
-            for (UsageStats stat : mCurrentStats) {
-                updateStatsLocked(stat, name,
-                        mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp,
-                        UsageStats.Event.CONTINUE_PREVIOUS_DAY);
-                mStatsChanged = true;
-            }
-        }
-        persistActiveStatsLocked();
-
-        final long totalTime = System.currentTimeMillis() - startTime;
-        Slog.i(TAG, "Rolling over usage stats complete. Took " + totalTime + " milliseconds");
+    @Override
+    public void onStatsUpdated() {
+        mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
     }
 
-    private void notifyStatsChangedLocked() {
-        if (!mStatsChanged) {
-            mStatsChanged = true;
-            mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
+    private void cleanUpRemovedUsersLocked() {
+        final List<UserInfo> users = mUserManager.getUsers(true);
+        if (users == null || users.size() == 0) {
+            throw new IllegalStateException("There can't be no users");
         }
+
+        ArraySet<String> toDelete = new ArraySet<>();
+        String[] fileNames = mUsageStatsDir.list();
+        if (fileNames == null) {
+            // No users to delete.
+            return;
+        }
+
+        toDelete.addAll(Arrays.asList(fileNames));
+
+        final int userCount = users.size();
+        for (int i = 0; i < userCount; i++) {
+            final UserInfo userInfo = users.get(i);
+            toDelete.remove(Integer.toString(userInfo.id));
+        }
+
+        final int deleteCount = toDelete.size();
+        for (int i = 0; i < deleteCount; i++) {
+            deleteRecursively(new File(mUsageStatsDir, toDelete.valueAt(i)));
+        }
+    }
+
+    private static void deleteRecursively(File f) {
+        File[] files = f.listFiles();
+        if (files != null) {
+            for (File subFile : files) {
+                deleteRecursively(subFile);
+            }
+        }
+
+        if (!f.delete()) {
+            Slog.e(TAG, "Failed to delete " + f);
+        }
+    }
+
+    private UserUsageStatsService getUserDataAndInitializeIfNeededLocked(int userId) {
+        UserUsageStatsService service = mUserState.get(userId);
+        if (service == null) {
+            service = new UserUsageStatsService(userId,
+                    new File(mUsageStatsDir, Integer.toString(userId)), this);
+            service.init();
+            mUserState.put(userId, service);
+        }
+        return service;
     }
 
     /**
@@ -189,58 +174,45 @@
     void shutdown() {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_REPORT_EVENT);
-            mHandler.removeMessages(MSG_FLUSH_TO_DISK);
-            persistActiveStatsLocked();
-        }
-    }
-
-    private static String eventToString(int eventType) {
-        switch (eventType) {
-            case UsageStats.Event.NONE:
-                return "NONE";
-            case UsageStats.Event.MOVE_TO_BACKGROUND:
-                return "MOVE_TO_BACKGROUND";
-            case UsageStats.Event.MOVE_TO_FOREGROUND:
-                return "MOVE_TO_FOREGROUND";
-            case UsageStats.Event.END_OF_DAY:
-                return "END_OF_DAY";
-            case UsageStats.Event.CONTINUE_PREVIOUS_DAY:
-                return "CONTINUE_PREVIOUS_DAY";
-            default:
-                return "UNKNOWN";
+            flushToDiskLocked();
         }
     }
 
     /**
      * Called by the Binder stub.
      */
-    void reportEvent(UsageStats.Event event) {
+    void reportEvent(UsageStats.Event event, int userId) {
         synchronized (mLock) {
-            if (DEBUG) {
-                Slog.d(TAG, "Got usage event for " + event.packageName
-                        + "[" + event.timeStamp + "]: "
-                        + eventToString(event.eventType));
-            }
-
-            if (event.timeStamp >= mDailyExpiryDate.getTimeInMillis()) {
-                // Need to rollover
-                rolloverStatsLocked();
-            }
-
-            mCurrentEvents.append(event.timeStamp, event);
-
-            for (UsageStats stats : mCurrentStats) {
-                updateStatsLocked(stats, event.packageName, event.timeStamp, event.eventType);
-            }
-            notifyStatsChangedLocked();
+            final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId);
+            service.reportEvent(event);
         }
     }
 
     /**
      * Called by the Binder stub.
      */
-    UsageStats[] getUsageStats(int bucketType, long beginTime) {
-        if (bucketType < 0 || bucketType >= mCurrentStats.length) {
+    void flushToDisk() {
+        synchronized (mLock) {
+            flushToDiskLocked();
+        }
+    }
+
+    /**
+     * Called by the Binder stub.
+     */
+    void removeUser(int userId) {
+        synchronized (mLock) {
+            Slog.i(TAG, "Removing user " + userId + " and all data.");
+            mUserState.remove(userId);
+            cleanUpRemovedUsersLocked();
+        }
+    }
+
+    /**
+     * Called by the Binder stub.
+     */
+    UsageStats[] getUsageStats(int userId, int bucketType, long beginTime) {
+        if (bucketType < 0 || bucketType >= UsageStatsManager.BUCKET_COUNT) {
             return UsageStats.EMPTY_STATS;
         }
 
@@ -250,110 +222,26 @@
         }
 
         synchronized (mLock) {
-            if (beginTime >= mCurrentStats[bucketType].mEndTimeStamp) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Requesting stats after " + beginTime + " but latest is "
-                            + mCurrentStats[bucketType].mEndTimeStamp);
-                }
-                // Nothing newer available.
-                return UsageStats.EMPTY_STATS;
-            } else if (beginTime >= mCurrentStats[bucketType].mBeginTimeStamp) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Returning in-memory stats");
-                }
-                // Fast path for retrieving in-memory state.
-                // TODO(adamlesinski): This copy just to parcel the object is wasteful.
-                // It would be nice to parcel it here and send that back, but the Binder API
-                // would need to change.
-                return new UsageStats[] { new UsageStats(mCurrentStats[bucketType]) };
-            } else {
-                // Flush any changes that were made to disk before we do a disk query.
-                persistActiveStatsLocked();
-            }
+            UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId);
+            return service.getUsageStats(bucketType, beginTime);
         }
-
-        if (DEBUG) {
-            Slog.d(TAG, "SELECT * FROM " + bucketType + " WHERE beginTime >= "
-                    + beginTime + " LIMIT " + USAGE_STAT_RESULT_LIMIT);
-        }
-
-        UsageStats[] results = mDatabase.getUsageStats(bucketType, beginTime,
-                USAGE_STAT_RESULT_LIMIT);
-
-        if (DEBUG) {
-            Slog.d(TAG, "Results: " + results.length);
-        }
-        return results;
     }
 
     /**
      * Called by the Binder stub.
      */
-    UsageStats.Event[] getEvents(long time) {
+    UsageStats.Event[] getEvents(int userId, long time) {
         return UsageStats.Event.EMPTY_EVENTS;
     }
 
-    private void loadActiveStatsLocked() {
-        final long timeNow = System.currentTimeMillis();
-
-        Calendar tempCal = mDailyExpiryDate;
-        for (int i = 0; i < mCurrentStats.length; i++) {
-            tempCal.setTimeInMillis(timeNow);
-            UsageStatsUtils.truncateDateTo(i, tempCal);
-
-            if (mCurrentStats[i] != null &&
-                    mCurrentStats[i].mBeginTimeStamp == tempCal.getTimeInMillis()) {
-                // These are the same, no need to load them (in memory stats are always newer
-                // than persisted stats).
-                continue;
-            }
-
-            UsageStats[] stats = mDatabase.getUsageStats(i, timeNow, 1);
-            if (stats != null && stats.length > 0) {
-                mCurrentStats[i] = stats[stats.length - 1];
-            } else {
-                mCurrentStats[i] = UsageStats.create(tempCal.getTimeInMillis(), timeNow);
-            }
+    private void flushToDiskLocked() {
+        final int userCount = mUserState.size();
+        for (int i = 0; i < userCount; i++) {
+            UserUsageStatsService service = mUserState.valueAt(i);
+            service.persistActiveStats();
         }
-        mStatsChanged = false;
-        mDailyExpiryDate.setTimeInMillis(timeNow);
-        mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1);
-        UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate);
-        Slog.i(TAG, "Rollover scheduled for " + sDateFormat.format(mDailyExpiryDate.getTime()));
-    }
 
-
-    private void persistActiveStatsLocked() {
-        if (mStatsChanged) {
-            Slog.i(TAG, "Flushing usage stats to disk");
-            try {
-                for (int i = 0; i < mCurrentStats.length; i++) {
-                    mDatabase.putUsageStats(i, mCurrentStats[i]);
-                }
-                mStatsChanged = false;
-                mHandler.removeMessages(MSG_FLUSH_TO_DISK);
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to persist active stats", e);
-            }
-        }
-    }
-
-    private void updateStatsLocked(UsageStats stats, String packageName, long timeStamp,
-            int eventType) {
-        PackageUsageStats pkgStats = stats.getOrCreatePackageUsageStats(packageName);
-
-        // TODO(adamlesinski): Ensure that we recover from incorrect event sequences
-        // like double MOVE_TO_BACKGROUND, etc.
-        if (eventType == UsageStats.Event.MOVE_TO_BACKGROUND ||
-                eventType == UsageStats.Event.END_OF_DAY) {
-            if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND ||
-                    pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) {
-                pkgStats.mTotalTimeSpent += timeStamp - pkgStats.mLastTimeUsed;
-            }
-        }
-        pkgStats.mLastEvent = eventType;
-        pkgStats.mLastTimeUsed = timeStamp;
-        stats.mEndTimeStamp = timeStamp;
+        mHandler.removeMessages(MSG_FLUSH_TO_DISK);
     }
 
     class H extends Handler {
@@ -365,13 +253,15 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_REPORT_EVENT:
-                    reportEvent((UsageStats.Event) msg.obj);
+                    reportEvent((UsageStats.Event) msg.obj, msg.arg1);
                     break;
 
                 case MSG_FLUSH_TO_DISK:
-                    synchronized (mLock) {
-                        persistActiveStatsLocked();
-                    }
+                    flushToDisk();
+                    break;
+
+                case MSG_REMOVE_USER:
+                    removeUser(msg.arg1);
                     break;
 
                 default:
@@ -401,9 +291,10 @@
                 return UsageStats.EMPTY_STATS;
             }
 
-            long token = Binder.clearCallingIdentity();
+            final int userId = UserHandle.getCallingUserId();
+            final long token = Binder.clearCallingIdentity();
             try {
-                return getUsageStats(bucketType, time);
+                return getUsageStats(userId, bucketType, time);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -415,9 +306,10 @@
                 return UsageStats.Event.EMPTY_EVENTS;
             }
 
-            long token = Binder.clearCallingIdentity();
+            final int userId = UserHandle.getCallingUserId();
+            final long token = Binder.clearCallingIdentity();
             try {
-                return getEvents(time);
+                return getEvents(userId, time);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -432,10 +324,11 @@
     private class LocalService extends UsageStatsManagerInternal {
 
         @Override
-        public void reportEvent(ComponentName component, long timeStamp, int eventType) {
+        public void reportEvent(ComponentName component, int userId,
+                long timeStamp, int eventType) {
             UsageStats.Event event = new UsageStats.Event(component.getPackageName(), timeStamp,
                     eventType);
-            mHandler.obtainMessage(MSG_REPORT_EVENT, event).sendToTarget();
+            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
         }
 
         @Override
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
new file mode 100644
index 0000000..d124188
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -0,0 +1,275 @@
+package com.android.server.usage;
+
+import android.app.usage.PackageUsageStats;
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+/**
+ * A per-user UsageStatsService. All methods are meant to be called with the main lock held
+ * in UsageStatsService.
+ */
+class UserUsageStatsService {
+    private static final String TAG = "UsageStatsService";
+    private static final boolean DEBUG = UsageStatsService.DEBUG;
+    private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    private final UsageStatsDatabase mDatabase;
+    private final UsageStats[] mCurrentStats = new UsageStats[UsageStatsManager.BUCKET_COUNT];
+    private boolean mStatsChanged = false;
+    private final Calendar mDailyExpiryDate;
+    private final StatsUpdatedListener mListener;
+    private final String mLogPrefix;
+
+    interface StatsUpdatedListener {
+        void onStatsUpdated();
+    }
+
+    UserUsageStatsService(int userId, File usageStatsDir, StatsUpdatedListener listener) {
+        mDailyExpiryDate = Calendar.getInstance();
+        mDatabase = new UsageStatsDatabase(usageStatsDir);
+        mListener = listener;
+        mLogPrefix = "User[" + Integer.toString(userId) + "] ";
+    }
+
+    void init() {
+        mDatabase.init();
+
+        int nullCount = 0;
+        for (int i = 0; i < mCurrentStats.length; i++) {
+            mCurrentStats[i] = mDatabase.getLatestUsageStats(i);
+            if (mCurrentStats[i] == null) {
+                nullCount++;
+            }
+        }
+
+        if (nullCount > 0) {
+            if (nullCount != mCurrentStats.length) {
+                // This is weird, but we shouldn't fail if something like this
+                // happens.
+                Slog.w(TAG, mLogPrefix + "Some stats have no latest available");
+            } else {
+                // This must be first boot.
+            }
+
+            // By calling loadActiveStats, we will
+            // generate new stats for each bucket.
+            loadActiveStats();
+        } else {
+            // Set up the expiry date to be one day from the latest daily stat.
+            // This may actually be today and we will rollover on the first event
+            // that is reported.
+            mDailyExpiryDate.setTimeInMillis(
+                    mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp);
+            mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1);
+            UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate);
+            Slog.i(TAG, mLogPrefix + "Rollover scheduled for "
+                    + sDateFormat.format(mDailyExpiryDate.getTime()));
+        }
+
+        // Now close off any events that were open at the time this was saved.
+        for (UsageStats stat : mCurrentStats) {
+            final int pkgCount = stat.getPackageCount();
+            for (int i = 0; i < pkgCount; i++) {
+                PackageUsageStats pkgStats = stat.getPackage(i);
+                if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND ||
+                        pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) {
+                    updateStats(stat, pkgStats.mPackageName, stat.mLastTimeSaved,
+                            UsageStats.Event.END_OF_DAY);
+                    notifyStatsChanged();
+                }
+            }
+        }
+    }
+
+    void reportEvent(UsageStats.Event event) {
+        if (DEBUG) {
+            Slog.d(TAG, mLogPrefix + "Got usage event for " + event.packageName
+                    + "[" + event.timeStamp + "]: "
+                    + eventToString(event.eventType));
+        }
+
+        if (event.timeStamp >= mDailyExpiryDate.getTimeInMillis()) {
+            // Need to rollover
+            rolloverStats();
+        }
+
+        for (UsageStats stats : mCurrentStats) {
+            updateStats(stats, event.packageName, event.timeStamp, event.eventType);
+        }
+
+        notifyStatsChanged();
+    }
+
+    UsageStats[] getUsageStats(int bucketType, long beginTime) {
+        if (beginTime >= mCurrentStats[bucketType].mEndTimeStamp) {
+            if (DEBUG) {
+                Slog.d(TAG, mLogPrefix + "Requesting stats after " + beginTime + " but latest is "
+                        + mCurrentStats[bucketType].mEndTimeStamp);
+            }
+            // Nothing newer available.
+            return UsageStats.EMPTY_STATS;
+
+        } else if (beginTime >= mCurrentStats[bucketType].mBeginTimeStamp) {
+            if (DEBUG) {
+                Slog.d(TAG, mLogPrefix + "Returning in-memory stats");
+            }
+            // Fast path for retrieving in-memory state.
+            // TODO(adamlesinski): This copy just to parcel the object is wasteful.
+            // It would be nice to parcel it here and send that back, but the Binder API
+            // would need to change.
+            return new UsageStats[] { new UsageStats(mCurrentStats[bucketType]) };
+
+        } else {
+            // Flush any changes that were made to disk before we do a disk query.
+            persistActiveStats();
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG, mLogPrefix + "SELECT * FROM " + bucketType + " WHERE beginTime >= "
+                    + beginTime + " LIMIT " + UsageStatsService.USAGE_STAT_RESULT_LIMIT);
+        }
+
+        final UsageStats[] results = mDatabase.getUsageStats(bucketType, beginTime,
+                UsageStatsService.USAGE_STAT_RESULT_LIMIT);
+
+        if (DEBUG) {
+            Slog.d(TAG, mLogPrefix + "Results: " + results.length);
+        }
+        return results;
+    }
+
+    void persistActiveStats() {
+        if (mStatsChanged) {
+            Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
+            try {
+                for (int i = 0; i < mCurrentStats.length; i++) {
+                    mDatabase.putUsageStats(i, mCurrentStats[i]);
+                }
+                mStatsChanged = false;
+            } catch (IOException e) {
+                Slog.e(TAG, mLogPrefix + "Failed to persist active stats", e);
+            }
+        }
+    }
+
+    private void rolloverStats() {
+        final long startTime = System.currentTimeMillis();
+        Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
+
+        // Finish any ongoing events with an END_OF_DAY event. Make a note of which components
+        // need a new CONTINUE_PREVIOUS_DAY entry.
+        ArraySet<String> continuePreviousDay = new ArraySet<>();
+        for (UsageStats stat : mCurrentStats) {
+            final int pkgCount = stat.getPackageCount();
+            for (int i = 0; i < pkgCount; i++) {
+                PackageUsageStats pkgStats = stat.getPackage(i);
+                if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND ||
+                        pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) {
+                    continuePreviousDay.add(pkgStats.mPackageName);
+                    updateStats(stat, pkgStats.mPackageName,
+                            mDailyExpiryDate.getTimeInMillis() - 1, UsageStats.Event.END_OF_DAY);
+                    mStatsChanged = true;
+                }
+            }
+        }
+
+        persistActiveStats();
+        mDatabase.prune();
+        loadActiveStats();
+
+        final int continueCount = continuePreviousDay.size();
+        for (int i = 0; i < continueCount; i++) {
+            String name = continuePreviousDay.valueAt(i);
+            for (UsageStats stat : mCurrentStats) {
+                updateStats(stat, name,
+                        mCurrentStats[UsageStatsManager.DAILY_BUCKET].mBeginTimeStamp,
+                        UsageStats.Event.CONTINUE_PREVIOUS_DAY);
+                mStatsChanged = true;
+            }
+        }
+        persistActiveStats();
+
+        final long totalTime = System.currentTimeMillis() - startTime;
+        Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
+                + " milliseconds");
+    }
+
+    private void notifyStatsChanged() {
+        if (!mStatsChanged) {
+            mStatsChanged = true;
+            mListener.onStatsUpdated();
+        }
+    }
+
+    private void loadActiveStats() {
+        final long timeNow = System.currentTimeMillis();
+
+        Calendar tempCal = mDailyExpiryDate;
+        for (int i = 0; i < mCurrentStats.length; i++) {
+            tempCal.setTimeInMillis(timeNow);
+            UsageStatsUtils.truncateDateTo(i, tempCal);
+
+            if (mCurrentStats[i] != null &&
+                    mCurrentStats[i].mBeginTimeStamp == tempCal.getTimeInMillis()) {
+                // These are the same, no need to load them (in memory stats are always newer
+                // than persisted stats).
+                continue;
+            }
+
+            UsageStats[] stats = mDatabase.getUsageStats(i, timeNow, 1);
+            if (stats != null && stats.length > 0) {
+                mCurrentStats[i] = stats[stats.length - 1];
+            } else {
+                mCurrentStats[i] = UsageStats.create(tempCal.getTimeInMillis(), timeNow);
+            }
+        }
+        mStatsChanged = false;
+        mDailyExpiryDate.setTimeInMillis(timeNow);
+        mDailyExpiryDate.add(Calendar.DAY_OF_YEAR, 1);
+        UsageStatsUtils.truncateDateTo(UsageStatsManager.DAILY_BUCKET, mDailyExpiryDate);
+        Slog.i(TAG, mLogPrefix + "Rollover scheduled for "
+                + sDateFormat.format(mDailyExpiryDate.getTime()));
+    }
+
+    private void updateStats(UsageStats stats, String packageName, long timeStamp,
+            int eventType) {
+        PackageUsageStats pkgStats = stats.getOrCreatePackageUsageStats(packageName);
+
+        // TODO(adamlesinski): Ensure that we recover from incorrect event sequences
+        // like double MOVE_TO_BACKGROUND, etc.
+        if (eventType == UsageStats.Event.MOVE_TO_BACKGROUND ||
+                eventType == UsageStats.Event.END_OF_DAY) {
+            if (pkgStats.mLastEvent == UsageStats.Event.MOVE_TO_FOREGROUND ||
+                    pkgStats.mLastEvent == UsageStats.Event.CONTINUE_PREVIOUS_DAY) {
+                pkgStats.mTotalTimeSpent += timeStamp - pkgStats.mLastTimeUsed;
+            }
+        }
+        pkgStats.mLastEvent = eventType;
+        pkgStats.mLastTimeUsed = timeStamp;
+        stats.mEndTimeStamp = timeStamp;
+    }
+
+    private static String eventToString(int eventType) {
+        switch (eventType) {
+            case UsageStats.Event.NONE:
+                return "NONE";
+            case UsageStats.Event.MOVE_TO_BACKGROUND:
+                return "MOVE_TO_BACKGROUND";
+            case UsageStats.Event.MOVE_TO_FOREGROUND:
+                return "MOVE_TO_FOREGROUND";
+            case UsageStats.Event.END_OF_DAY:
+                return "END_OF_DAY";
+            case UsageStats.Event.CONTINUE_PREVIOUS_DAY:
+                return "CONTINUE_PREVIOUS_DAY";
+            default:
+                return "UNKNOWN";
+        }
+    }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index 1e0d6de..8913eb9 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -28,8 +28,6 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.UUID;
 
 /**
@@ -39,43 +37,35 @@
  */
 public class DatabaseHelper extends SQLiteOpenHelper {
     static final String TAG = "SoundModelDBHelper";
-    static final boolean DBG = false;
+    // TODO: Set to false.
+    static final boolean DBG = true;
 
     private static final String NAME = "sound_model.db";
-    private static final int VERSION = 2;
-
-    public static interface KeyphraseContract {
-        public static final String TABLE = "keyphrase";
-        public static final String KEY_ID = "_id";
-        public static final String KEY_RECOGNITION_MODES = "modes";
-        public static final String KEY_LOCALE = "locale";
-        public static final String KEY_HINT_TEXT = "hint_text";
-        public static final String KEY_USERS = "users";
-        public static final String KEY_SOUND_MODEL_ID = "sound_model_id";
-    }
+    private static final int VERSION = 3;
 
     public static interface SoundModelContract {
         public static final String TABLE = "sound_model";
-        public static final String KEY_ID = "_id";
+        public static final String KEY_KEYPHRASE_ID = "keyphrase_id";
+        public static final String KEY_MODEL_UUID = "model_uuid";
         public static final String KEY_TYPE = "type";
         public static final String KEY_DATA = "data";
+        public static final String KEY_RECOGNITION_MODES = "recognition_modes";
+        public static final String KEY_LOCALE = "locale";
+        public static final String KEY_HINT_TEXT = "hint_text";
+        public static final String KEY_USERS = "users";
     }
 
-    // Table Create Statements
-    private static final String CREATE_TABLE_KEYPRHASES = "CREATE TABLE "
-            + KeyphraseContract.TABLE + "("
-            + KeyphraseContract.KEY_ID + " INTEGER PRIMARY KEY,"
-            + KeyphraseContract.KEY_RECOGNITION_MODES + " INTEGER,"
-            + KeyphraseContract.KEY_USERS + " TEXT,"
-            + KeyphraseContract.KEY_SOUND_MODEL_ID + " TEXT,"
-            + KeyphraseContract.KEY_LOCALE + " TEXT,"
-            + KeyphraseContract.KEY_HINT_TEXT + " TEXT" + ")";
-
+    // Table Create Statement
     private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
             + SoundModelContract.TABLE + "("
-            + SoundModelContract.KEY_ID + " TEXT PRIMARY KEY,"
+            + SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER PRIMARY KEY,"
+            + SoundModelContract.KEY_MODEL_UUID + " TEXT,"
             + SoundModelContract.KEY_TYPE + " INTEGER,"
-            + SoundModelContract.KEY_DATA + " BLOB" + ")";
+            + SoundModelContract.KEY_DATA + " BLOB,"
+            + SoundModelContract.KEY_RECOGNITION_MODES + " INTEGER,"
+            + SoundModelContract.KEY_LOCALE + " TEXT,"
+            + SoundModelContract.KEY_HINT_TEXT + " TEXT,"
+            + SoundModelContract.KEY_USERS + " TEXT" + ")";
 
     private final UserManager mUserManager;
 
@@ -87,57 +77,44 @@
     @Override
     public void onCreate(SQLiteDatabase db) {
         // creating required tables
-        db.execSQL(CREATE_TABLE_KEYPRHASES);
         db.execSQL(CREATE_TABLE_SOUND_MODEL);
     }
 
     @Override
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
         // TODO: For now, drop older tables and recreate new ones.
-        db.execSQL("DROP TABLE IF EXISTS " + KeyphraseContract.TABLE);
         db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
         onCreate(db);
     }
 
-    public boolean addOrUpdateKeyphraseSoundModel(KeyphraseSoundModel soundModel) {
+    /**
+     * Updates the given keyphrase model, adds it, if it doesn't already exist.
+     *
+     * TODO: We only support one keyphrase currently.
+     */
+    public boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel) {
         synchronized(this) {
             SQLiteDatabase db = getWritableDatabase();
             ContentValues values = new ContentValues();
-            // Generate a random ID for the model.
-            values.put(SoundModelContract.KEY_ID, soundModel.uuid.toString());
-            values.put(SoundModelContract.KEY_DATA, soundModel.data);
+            values.put(SoundModelContract.KEY_MODEL_UUID, soundModel.uuid.toString());
             values.put(SoundModelContract.KEY_TYPE, SoundTrigger.SoundModel.TYPE_KEYPHRASE);
-    
-            boolean status = true;
-            if (db.insertWithOnConflict(SoundModelContract.TABLE, null, values,
-                    SQLiteDatabase.CONFLICT_REPLACE) != -1) {
-                for (Keyphrase keyphrase : soundModel.keyphrases) {
-                    status &= addOrUpdateKeyphraseLocked(db, soundModel.uuid, keyphrase);
-                }
-                db.close();
-                return status;
-            } else {
-                Slog.w(TAG, "Failed to persist sound model to database");
-                db.close();
-                return false;
-            }
-        }
-    }
+            values.put(SoundModelContract.KEY_DATA, soundModel.data);
 
-    private boolean addOrUpdateKeyphraseLocked(
-            SQLiteDatabase db, UUID modelId, Keyphrase keyphrase) {
-        ContentValues values = new ContentValues();
-        values.put(KeyphraseContract.KEY_ID, keyphrase.id);
-        values.put(KeyphraseContract.KEY_RECOGNITION_MODES, keyphrase.recognitionModes);
-        values.put(KeyphraseContract.KEY_SOUND_MODEL_ID, modelId.toString());
-        values.put(KeyphraseContract.KEY_HINT_TEXT, keyphrase.text);
-        values.put(KeyphraseContract.KEY_LOCALE, keyphrase.locale);
-        values.put(KeyphraseContract.KEY_USERS, getCommaSeparatedString(keyphrase.users));
-        if (db.insertWithOnConflict(
-                KeyphraseContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1) {
-            return true;
-        } else {
-            Slog.w(TAG, "Failed to persist keyphrase to database");
+            if (soundModel.keyphrases != null && soundModel.keyphrases.length == 1) {
+                values.put(SoundModelContract.KEY_KEYPHRASE_ID, soundModel.keyphrases[0].id);
+                values.put(SoundModelContract.KEY_RECOGNITION_MODES,
+                        soundModel.keyphrases[0].recognitionModes);
+                values.put(SoundModelContract.KEY_USERS,
+                        getCommaSeparatedString(soundModel.keyphrases[0].users));
+                values.put(SoundModelContract.KEY_LOCALE, soundModel.keyphrases[0].locale);
+                values.put(SoundModelContract.KEY_HINT_TEXT, soundModel.keyphrases[0].text);
+                try {
+                    return db.insertWithOnConflict(SoundModelContract.TABLE, null, values,
+                            SQLiteDatabase.CONFLICT_REPLACE) != -1;
+                } finally {
+                    db.close();
+                }
+            }
             return false;
         }
     }
@@ -145,111 +122,90 @@
     /**
      * Deletes the sound model and associated keyphrases.
      */
-    public boolean deleteKeyphraseSoundModel(UUID uuid) {
+    public boolean deleteKeyphraseSoundModel(int keyphraseId) {
         synchronized(this) {
             SQLiteDatabase db = getWritableDatabase();
-            String modelId = uuid.toString();
-            String soundModelClause = SoundModelContract.KEY_ID + "=" + modelId;
-            boolean status = true;
-            if (db.delete(SoundModelContract.TABLE, soundModelClause, null) == 0) {
-                Slog.w(TAG, "No sound models deleted from the database");
-                status = false;
+            String soundModelClause = SoundModelContract.KEY_KEYPHRASE_ID + "=" + keyphraseId;
+
+            try {
+                return db.delete(SoundModelContract.TABLE, soundModelClause, null) != 0;
+            } finally {
+                db.close();
             }
-            String keyphraseClause = KeyphraseContract.KEY_SOUND_MODEL_ID + "=" + modelId;
-            if (db.delete(KeyphraseContract.TABLE, keyphraseClause, null) == 0) {
-                Slog.w(TAG, "No keyphrases deleted from the database");
-                status = false;
-            }
-            db.close();
-            return status;
         }
     }
 
     /**
-     * Lists all the keyphrase sound models currently registered with the system.
+     * Returns a matching {@link KeyphraseSoundModel} for the keyphrase ID.
+     * Returns null if a match isn't found.
+     *
+     * TODO: We only support one keyphrase currently.
      */
-    public List<KeyphraseSoundModel> getKephraseSoundModels() {
+    public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId) {
         synchronized(this) {
-            List<KeyphraseSoundModel> models = new ArrayList<>();
-            String selectQuery = "SELECT  * FROM " + SoundModelContract.TABLE;
+            // Find the corresponding sound model ID for the keyphrase.
+            String selectQuery = "SELECT  * FROM " + SoundModelContract.TABLE
+                    + " WHERE " + SoundModelContract.KEY_KEYPHRASE_ID + " = '" + keyphraseId + "'";
             SQLiteDatabase db = getReadableDatabase();
             Cursor c = db.rawQuery(selectQuery, null);
-    
-            // looping through all rows and adding to list
-            if (c.moveToFirst()) {
-                do {
+
+            try {
+                if (c.moveToFirst()) {
                     int type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
                     if (type != SoundTrigger.SoundModel.TYPE_KEYPHRASE) {
-                        // Ignore non-keyphrase sound models.
-                        continue;
+                        Slog.w(TAG, "No KeyphraseSoundModel available for the given keyphrase");
+                        return null;
                     }
-                    String id = c.getString(c.getColumnIndex(SoundModelContract.KEY_ID));
-                    byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
-                    // Get all the keyphrases for this this sound model.
-                    // Validate the sound model.
-                    if (id == null) {
+
+                    String modelUuid = c.getString(
+                            c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
+                    if (modelUuid == null) {
                         Slog.w(TAG, "Ignoring sound model since it doesn't specify an ID");
-                        continue;
+                        return null;
                     }
-                    KeyphraseSoundModel model = new KeyphraseSoundModel(
-                            UUID.fromString(id), data, getKeyphrasesForSoundModelLocked(db, id));
-                    if (DBG) {
-                        Slog.d(TAG, "Adding model: " + model);
+
+                    byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
+                    int recognitionModes = c.getInt(
+                            c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
+                    int[] users = getArrayForCommaSeparatedString(
+                            c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS)));
+                    String locale = c.getString(c.getColumnIndex(SoundModelContract.KEY_LOCALE));
+                    String text = c.getString(
+                            c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
+
+                    // Only add keyphrases meant for the current user.
+                    if (users == null) {
+                        // No users present in the keyphrase.
+                        Slog.w(TAG, "Ignoring keyphrase since it doesn't specify users");
+                        return null;
                     }
-                    models.add(model);
-                } while (c.moveToNext());
+                    boolean isAvailableForCurrentUser = false;
+                    int currentUser = mUserManager.getUserHandle();
+                    for (int user : users) {
+                        if (currentUser == user) {
+                            isAvailableForCurrentUser = true;
+                            break;
+                        }
+                    }
+                    if (!isAvailableForCurrentUser) {
+                        Slog.w(TAG, "Ignoring keyphrase since it's not for the current user");
+                        return null;
+                    }
+
+                    Keyphrase[] keyphrases = new Keyphrase[1];
+                    keyphrases[0] = new Keyphrase(
+                            keyphraseId, recognitionModes, locale, text, users);
+                    return new KeyphraseSoundModel(UUID.fromString(modelUuid), data, keyphrases);
+                }
+                Slog.w(TAG, "No SoundModel available for the given keyphrase");
+            } finally {
+                c.close();
+                db.close();
             }
-            c.close();
-            db.close();
-            return models;
+            return null;
         }
     }
 
-    private Keyphrase[] getKeyphrasesForSoundModelLocked(SQLiteDatabase db, String modelId) {
-        List<Keyphrase> keyphrases = new ArrayList<>();
-        String selectQuery = "SELECT  * FROM " + KeyphraseContract.TABLE
-                + " WHERE " + KeyphraseContract.KEY_SOUND_MODEL_ID + " = '" + modelId + "'";
-        Cursor c = db.rawQuery(selectQuery, null);
-
-        // looping through all rows and adding to list
-        if (c.moveToFirst()) {
-            do {
-                int id = c.getInt(c.getColumnIndex(KeyphraseContract.KEY_ID));
-                int modes = c.getInt(c.getColumnIndex(KeyphraseContract.KEY_RECOGNITION_MODES));
-                int[] users = getArrayForCommaSeparatedString(
-                        c.getString(c.getColumnIndex(KeyphraseContract.KEY_USERS)));
-                String locale = c.getString(c.getColumnIndex(KeyphraseContract.KEY_LOCALE));
-                String hintText = c.getString(c.getColumnIndex(KeyphraseContract.KEY_HINT_TEXT));
-
-                // Only add keyphrases meant for the current user.
-                if (users == null) {
-                    // No users present in the keyphrase.
-                    Slog.w(TAG, "Ignoring keyphrase since it doesn't specify users");
-                    continue;
-                }
-                boolean isAvailableForCurrentUser = false;
-                int currentUser = mUserManager.getUserHandle();
-                for (int user : users) {
-                    if (currentUser == user) {
-                        isAvailableForCurrentUser = true;
-                        break;
-                    }
-                }
-                if (!isAvailableForCurrentUser) {
-                    Slog.w(TAG, "Ignoring keyphrase since it's not for the current user");
-                    continue;
-                }
-
-                keyphrases.add(new Keyphrase(id, modes, locale, hintText, users));
-            } while (c.moveToNext());
-        }
-        Keyphrase[] keyphraseArr = new Keyphrase[keyphrases.size()];
-        keyphrases.toArray(keyphraseArr);
-        c.close();
-        return keyphraseArr;
-    }
-
-
     private static String getCommaSeparatedString(int[] users) {
         if (users == null || users.length == 0) {
             return "";
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 4430586..1e4a518 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -38,7 +38,8 @@
  */
 public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     static final String TAG = "SoundTriggerHelper";
-    static final boolean DBG = false;
+    // TODO: Set to false.
+    static final boolean DBG = true;
     // TODO: Remove this.
     static final int TEMP_KEYPHRASE_ID = 100;
 
@@ -237,20 +238,13 @@
 
         switch (event.status) {
             case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
-                // TODO: Pass the captured audio back.
                 try {
-                    listener.onDetected(null);
+                    listener.onDetected(event);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "RemoteException in onDetected");
                 }
                 break;
-            case SoundTrigger.RECOGNITION_STATUS_ABORT:
-                try {
-                    listener.onDetectionStopped();
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "RemoteException in onDetectionStopped");
-                }
-                break;
+            case SoundTrigger.RECOGNITION_STATUS_ABORT: // fall-through
             case SoundTrigger.RECOGNITION_STATUS_FAILURE:
                 try {
                     listener.onDetectionStopped();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 5d9e107..a3d578a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -50,6 +50,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.UUID;
 
 
 /**
@@ -243,34 +244,18 @@
         //----------------- Model management APIs --------------------------------//
 
         @Override
-        public List<KeyphraseSoundModel> listRegisteredKeyphraseSoundModels(
-                IVoiceInteractionService service) {
-            // Allow the call if this is the current voice interaction service
-            // or the caller holds the MANAGE_VOICE_KEYPHRASES permission.
+        public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId) {
             synchronized (this) {
-                boolean permissionGranted =
-                        mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
-                        == PackageManager.PERMISSION_GRANTED;
-                boolean currentVoiceInteractionService = service != null
-                        && mImpl != null
-                        && mImpl.mService != null
-                        && service.asBinder() == mImpl.mService.asBinder();
-
-                if (!permissionGranted && !currentVoiceInteractionService) {
-                    if (!currentVoiceInteractionService) {
-                        throw new SecurityException(
-                                "Caller is not the current voice interaction service");
-                    }
-                    if (!permissionGranted) {
-                        throw new SecurityException("Caller does not hold the permission "
-                                + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
-                    }
+                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Caller does not hold the permission "
+                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
                 }
             }
 
             final long caller = Binder.clearCallingIdentity();
             try {
-                return mDbHelper.getKephraseSoundModels();
+                return mDbHelper.getKeyphraseSoundModel(keyphraseId);
             } finally {
                 Binder.restoreCallingIdentity(caller);
             }
@@ -291,15 +276,35 @@
 
             final long caller = Binder.clearCallingIdentity();
             try {
-                boolean success = false;
-                if (model.keyphrases == null) {
-                    // If the keyphrases are not present in the model, delete the model.
-                    success = mDbHelper.deleteKeyphraseSoundModel(model.uuid);
+                if (mDbHelper.updateKeyphraseSoundModel(model)) {
+                    synchronized (this) {
+                        // Notify the voice interaction service of a change in sound models.
+                        if (mImpl != null && mImpl.mService != null) {
+                            mImpl.notifySoundModelsChangedLocked();
+                        }
+                    }
+                    return SoundTriggerHelper.STATUS_OK;
                 } else {
-                    // Else update the model.
-                    success = mDbHelper.addOrUpdateKeyphraseSoundModel(model);
+                    return SoundTriggerHelper.STATUS_ERROR;
                 }
-                if (success) {
+            } finally {
+                Binder.restoreCallingIdentity(caller);
+            }
+        }
+
+        @Override
+        public int deleteKeyphraseSoundModel(int keyphraseId) {
+            synchronized (this) {
+                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Caller does not hold the permission "
+                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
+                }
+            }
+
+            final long caller = Binder.clearCallingIdentity();
+            try {
+                if (mDbHelper.deleteKeyphraseSoundModel(keyphraseId)) {
                     synchronized (this) {
                         // Notify the voice interaction service of a change in sound models.
                         if (mImpl != null && mImpl.mService != null) {
@@ -317,6 +322,25 @@
 
         //----------------- SoundTrigger APIs --------------------------------//
         @Override
+        public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId) {
+            synchronized (this) {
+                if (mImpl == null || mImpl.mService == null
+                        || service.asBinder() != mImpl.mService.asBinder()) {
+                    throw new SecurityException(
+                            "Caller is not the current voice interaction service");
+                }
+            }
+
+            final long caller = Binder.clearCallingIdentity();
+            try {
+                KeyphraseSoundModel model = mDbHelper.getKeyphraseSoundModel(keyphraseId);
+                return model != null;
+            } finally {
+                Binder.restoreCallingIdentity(caller);
+            }
+        }
+
+        @Override
         public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
@@ -337,8 +361,7 @@
 
         @Override
         public int startRecognition(IVoiceInteractionService service, int keyphraseId,
-                KeyphraseSoundModel soundModel, IRecognitionStatusCallback callback,
-                RecognitionConfig recognitionConfig) {
+                IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
                 if (mImpl == null || mImpl.mService == null
@@ -347,13 +370,25 @@
                             "Caller is not the current voice interaction service");
                 }
 
-                final long caller = Binder.clearCallingIdentity();
-                try {
+                if (callback == null || recognitionConfig == null) {
+                    throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
+                }
+            }
+
+            final long caller = Binder.clearCallingIdentity();
+            try {
+                KeyphraseSoundModel soundModel = mDbHelper.getKeyphraseSoundModel(keyphraseId);
+                if (soundModel == null
+                        || soundModel.uuid == null
+                        || soundModel.keyphrases == null) {
+                    Slog.w(TAG, "No matching sound model found in startRecognition");
+                    return SoundTriggerHelper.STATUS_ERROR;
+                } else {
                     return mSoundTriggerHelper.startRecognition(
                             keyphraseId, soundModel, callback, recognitionConfig);
-                } finally {
-                    Binder.restoreCallingIdentity(caller);
                 }
+            } finally {
+                Binder.restoreCallingIdentity(caller);
             }
         }
 
@@ -367,13 +402,13 @@
                     throw new SecurityException(
                             "Caller is not the current voice interaction service");
                 }
+            }
 
-                final long caller = Binder.clearCallingIdentity();
-                try {
-                    return mSoundTriggerHelper.stopRecognition(keyphraseId, callback);
-                } finally {
-                    Binder.restoreCallingIdentity(caller);
-                }
+            final long caller = Binder.clearCallingIdentity();
+            try {
+                return mSoundTriggerHelper.stopRecognition(keyphraseId, callback);
+            } finally {
+                Binder.restoreCallingIdentity(caller);
             }
         }
 
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index ad5c614..838f221 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -18,9 +18,9 @@
 
 import android.app.PendingIntent;
 import android.net.Uri;
-import android.os.RemoteException;
 import android.telephony.DisconnectCause;
 
+import java.lang.String;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -309,15 +309,13 @@
         public void onPostDialWait(Call call, String remainingPostDialSequence) {}
 
         /**
-         * Invoked when the {@code RemoteCallVideoProvider} of the {@code Call} has changed.
+         * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
          *
          * @param call The {@code Call} invoking this method.
-         * @param callVideoProvider The {@code RemoteCallVideoProvider} associated with the
-         * {@code Call}.
+         * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
          */
 
-        public void onCallVideoProviderChanged(Call call,
-                RemoteCallVideoProvider callVideoProvider) {}
+        public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
 
         /**
          * Launches an activity for this connection on top of the in-call UI.
@@ -348,7 +346,7 @@
     private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
     private List<String> mCannedTextResponses = null;
     private String mRemainingPostDialSequence;
-    private RemoteCallVideoProvider mCallVideoProvider;
+    private InCallService.VideoCall mVideoCall;
     private Details mDetails;
     private final List<Listener> mListeners = new ArrayList<>();
 
@@ -533,10 +531,10 @@
     /**
      * Obtains an object that can be used to display video from this {@code Call}.
      *
-     * @return An {@code ICallVideoProvider}.
+     * @return An {@code Call.VideoCall}.
      */
-    public RemoteCallVideoProvider getCallVideoProvider() {
-        return mCallVideoProvider;
+    public InCallService.VideoCall getVideoCall() {
+        return mVideoCall;
     }
 
     /**
@@ -609,14 +607,9 @@
                     Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
         }
 
-        boolean callVideoProviderChanged = false;
-        try {
-            callVideoProviderChanged =
-                    !Objects.equals(mCallVideoProvider, parcelableCall.getCallVideoProvider());
-            if (callVideoProviderChanged) {
-                mCallVideoProvider = parcelableCall.getCallVideoProvider();
-            }
-        } catch (RemoteException e) {
+        boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
+        if (videoCallChanged) {
+            mVideoCall = parcelableCall.getVideoCall();
         }
 
         int state = stateFromParcelableCallState(parcelableCall.getState());
@@ -649,8 +642,8 @@
         if (cannedTextResponsesChanged) {
             fireCannedTextResponsesLoaded(mCannedTextResponses);
         }
-        if (callVideoProviderChanged) {
-            fireCallVideoProviderChanged(mCallVideoProvider);
+        if (videoCallChanged) {
+            fireVideoCallChanged(mVideoCall);
         }
 
         // If we have transitioned to DISCONNECTED, that means we need to notify clients and
@@ -715,10 +708,10 @@
         }
     }
 
-    private void fireCallVideoProviderChanged(RemoteCallVideoProvider callVideoProvider) {
+    private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
         Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
         for (int i = 0; i < listeners.length; i++) {
-            listeners[i].onCallVideoProviderChanged(this, callVideoProvider);
+            listeners[i].onVideoCallChanged(this, videoCall);
         }
     }
 
@@ -773,4 +766,4 @@
                 return STATE_NEW;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/CallVideoClient.java b/telecomm/java/android/telecomm/CallVideoClient.java
deleted file mode 100644
index 00473ff..0000000
--- a/telecomm/java/android/telecomm/CallVideoClient.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telecomm;
-
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-
-import com.android.internal.os.SomeArgs;
-import com.android.internal.telecomm.ICallVideoClient;
-
-/**
- * Base implementation of a CallVideoClient which communicates changes to video properties of a call
- * from the framework to the current InCall-UI.
- */
-public abstract class CallVideoClient {
-
-    /**
-     * Video is not being received (no protocol pause was issued).
-     */
-    public static final int SESSION_EVENT_RX_PAUSE = 1;
-
-    /**
-     * Video reception has resumed after a SESSION_EVENT_RX_PAUSE.
-     */
-    public static final int SESSION_EVENT_RX_RESUME = 2;
-
-    /**
-     * Video transmission has begun. This occurs after a negotiated start of video transmission
-     * when the underlying protocol has actually begun transmitting video to the remote party.
-     */
-    public static final int SESSION_EVENT_TX_START = 3;
-
-    /**
-     * Video transmission has stopped. This occur after a negotiated stop of video transmission when
-     * the underlying protocol has actually stopped transmitting video to the remote party.
-     */
-    public static final int SESSION_EVENT_TX_STOP = 4;
-
-    /**
-     * Session modify request was successful.
-     */
-    public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
-
-    /**
-     * Session modify request failed.
-     */
-    public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
-
-    /**
-     * Session modify request ignored due to invalid parameters.
-     */
-    public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
-
-    private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
-    private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
-    private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
-    private static final int MSG_UPDATE_PEER_DIMENSIONS = 4;
-    private static final int MSG_UPDATE_CALL_DATA_USAGE = 5;
-    private static final int MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE = 6;
-
-    /** Default Handler used to consolidate binder method calls onto a single thread. */
-    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
-                    onReceiveSessionModifyRequest((VideoCallProfile) msg.obj);
-                    break;
-                case MSG_RECEIVE_SESSION_MODIFY_RESPONSE: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        int status = (int) args.arg1;
-                        VideoCallProfile requestProfile = (VideoCallProfile) args.arg2;
-                        VideoCallProfile responseProfile = (VideoCallProfile) args.arg3;
-
-                        onReceiveSessionModifyResponse(status, requestProfile,
-                                responseProfile);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_HANDLE_CALL_SESSION_EVENT:
-                    onHandleCallSessionEvent((int) msg.obj);
-                    break;
-                case MSG_UPDATE_PEER_DIMENSIONS: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        int width = (int) args.arg1;
-                        int height = (int) args.arg2;
-                        onUpdatePeerDimensions(width, height);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_UPDATE_CALL_DATA_USAGE:
-                    onUpdateCallDataUsage(msg.arg1);
-                    break;
-                case MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE:
-                    onHandleCameraCapabilitiesChange((CallCameraCapabilities) msg.obj);
-                    break;
-                default:
-                    break;
-            }
-        }
-    };
-
-    /**
-     * Default ICallVideoClient implementation.
-     */
-    private final class CallVideoClientBinder extends ICallVideoClient.Stub {
-        @Override
-        public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
-            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST,
-                    videoCallProfile).sendToTarget();
-        }
-
-        @Override
-        public void receiveSessionModifyResponse(int status,
-                VideoCallProfile requestProfile, VideoCallProfile responseProfile) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = status;
-            args.arg2 = requestProfile;
-            args.arg3 = responseProfile;
-            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
-        }
-
-        @Override
-        public void handleCallSessionEvent(int event) {
-            mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget();
-        }
-
-        @Override
-        public void updatePeerDimensions(int width, int height) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = width;
-            args.arg2 = height;
-            mHandler.obtainMessage(MSG_UPDATE_PEER_DIMENSIONS, args).sendToTarget();
-        }
-
-        @Override
-        public void updateCallDataUsage(int dataUsage) {
-            mHandler.obtainMessage(MSG_UPDATE_CALL_DATA_USAGE, dataUsage).sendToTarget();
-        }
-
-        @Override
-        public void handleCameraCapabilitiesChange(CallCameraCapabilities cameraCapabilities) {
-            mHandler.obtainMessage(MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE,
-                    cameraCapabilities).sendToTarget();
-        }
-    }
-
-    private final CallVideoClientBinder mBinder;
-
-    public CallVideoClient() {
-        mBinder = new CallVideoClientBinder();
-    }
-
-    /**
-     * Returns binder object which can be used across IPC methods.
-     * @hide
-     */
-    public final IBinder getBinder() {
-        return mBinder;
-    }
-
-    /**
-     * Called when a session modification request is received from the remote device.
-     * The remote request is sent via {@link CallVideoProvider#onSendSessionModifyRequest}.
-     * The InCall UI is responsible for potentially prompting the user whether they wish to accept
-     * the new call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a
-     * video call) and should call {@link CallVideoProvider#onSendSessionModifyResponse} to indicate
-     * the video settings the user has agreed to.
-     *
-     * @param videoCallProfile The requested video call profile.
-     */
-    public abstract void onReceiveSessionModifyRequest(VideoCallProfile videoCallProfile);
-
-    /**
-     * Called when a response to a session modification request is received from the remote device.
-     * The remote InCall UI sends the response using
-     * {@link CallVideoProvider#onSendSessionModifyResponse}.
-     *
-     * @param status Status of the session modify request.  Valid values are
-     *               {@link CallVideoClient#SESSION_MODIFY_REQUEST_SUCCESS},
-     *               {@link CallVideoClient#SESSION_MODIFY_REQUEST_FAIL},
-     *               {@link CallVideoClient#SESSION_MODIFY_REQUEST_INVALID}
-     * @param requestProfile The original request which was sent to the remote device.
-     * @param responseProfile The actual profile changes made by the remote device.
-     */
-    public abstract void onReceiveSessionModifyResponse(int status,
-            VideoCallProfile requestProfile, VideoCallProfile responseProfile);
-
-    /**
-     * Handles events related to the current session which the client may wish to handle.  These
-     * are separate from requested changes to the session due to the underlying protocol or
-     * connection.
-     * Valid values are: {@link CallVideoClient#SESSION_EVENT_RX_PAUSE},
-     * {@link CallVideoClient#SESSION_EVENT_RX_RESUME},
-     * {@link CallVideoClient#SESSION_EVENT_TX_START}, {@link CallVideoClient#SESSION_EVENT_TX_STOP}
-     *
-     * @param event The event.
-     */
-    public abstract void onHandleCallSessionEvent(int event);
-
-    /**
-     * Handles a change to the video dimensions from the remote caller (peer).  This could happen
-     * if, for example, the peer changes orientation of their device.
-     *
-     * @param width  The updated peer video width.
-     * @param height The updated peer video height.
-     */
-    public abstract void onUpdatePeerDimensions(int width, int height);
-
-    /**
-     * Handles an update to the total data used for the current session.
-     *
-     * @param dataUsage The updated data usage.
-     */
-    public abstract void onUpdateCallDataUsage(int dataUsage);
-
-    /**
-     * Handles a change in camera capabilities.
-     *
-     * @param callCameraCapabilities The changed camera capabilities.
-     */
-    public abstract void onHandleCameraCapabilitiesChange(
-            CallCameraCapabilities callCameraCapabilities);
-}
-
diff --git a/telecomm/java/android/telecomm/CallVideoProvider.java b/telecomm/java/android/telecomm/CallVideoProvider.java
deleted file mode 100644
index 443a5b6..0000000
--- a/telecomm/java/android/telecomm/CallVideoProvider.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telecomm;
-
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.view.Surface;
-
-import com.android.internal.telecomm.ICallVideoClient;
-import com.android.internal.telecomm.ICallVideoProvider;
-
-public abstract class CallVideoProvider {
-    private static final int MSG_SET_CALL_VIDEO_CLIENT = 1;
-    private static final int MSG_SET_CAMERA = 2;
-    private static final int MSG_SET_PREVIEW_SURFACE = 3;
-    private static final int MSG_SET_DISPLAY_SURFACE = 4;
-    private static final int MSG_SET_DEVICE_ORIENTATION = 5;
-    private static final int MSG_SET_ZOOM = 6;
-    private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
-    private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
-    private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
-    private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
-    private static final int MSG_SET_PAUSE_IMAGE = 11;
-
-    /**
-     * Default handler used to consolidate binder method calls onto a single thread.
-     */
-    private final class CallVideoProviderHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_SET_CALL_VIDEO_CLIENT:
-                    try {
-                        ICallVideoClient callVideoClient =
-                                ICallVideoClient.Stub.asInterface((IBinder) msg.obj);
-                        RemoteCallVideoClient remoteCallVideoClient =
-                                new RemoteCallVideoClient(callVideoClient);
-                        onSetCallVideoClient(remoteCallVideoClient);
-                    } catch (RemoteException ignored) {
-                    }
-                    break;
-                case MSG_SET_CAMERA:
-                    onSetCamera((String) msg.obj);
-                    break;
-                case MSG_SET_PREVIEW_SURFACE:
-                    onSetPreviewSurface((Surface) msg.obj);
-                    break;
-                case MSG_SET_DISPLAY_SURFACE:
-                    onSetDisplaySurface((Surface) msg.obj);
-                    break;
-                case MSG_SET_DEVICE_ORIENTATION:
-                    onSetDeviceOrientation(msg.arg1);
-                    break;
-                case MSG_SET_ZOOM:
-                    onSetZoom((Float) msg.obj);
-                    break;
-                case MSG_SEND_SESSION_MODIFY_REQUEST:
-                    onSendSessionModifyRequest((VideoCallProfile) msg.obj);
-                    break;
-                case MSG_SEND_SESSION_MODIFY_RESPONSE:
-                    onSendSessionModifyResponse((VideoCallProfile) msg.obj);
-                    break;
-                case MSG_REQUEST_CAMERA_CAPABILITIES:
-                    onRequestCameraCapabilities();
-                    break;
-                case MSG_REQUEST_CALL_DATA_USAGE:
-                    onRequestCallDataUsage();
-                    break;
-                case MSG_SET_PAUSE_IMAGE:
-                    onSetPauseImage((String) msg.obj);
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Default ICallVideoProvider implementation.
-     */
-    private final class CallVideoProviderBinder extends ICallVideoProvider.Stub {
-        public void setCallVideoClient(IBinder callVideoClientBinder) {
-            mMessageHandler.obtainMessage(
-                    MSG_SET_CALL_VIDEO_CLIENT, callVideoClientBinder).sendToTarget();
-        }
-
-        public void setCamera(String cameraId) {
-            mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
-        }
-
-        public void setPreviewSurface(Surface surface) {
-            mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
-        }
-
-        public void setDisplaySurface(Surface surface) {
-            mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
-        }
-
-        public void setDeviceOrientation(int rotation) {
-            mMessageHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation).sendToTarget();
-        }
-
-        public void setZoom(float value) {
-            mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
-        }
-
-        public void sendSessionModifyRequest(VideoCallProfile requestProfile) {
-            mMessageHandler.obtainMessage(
-                    MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget();
-        }
-
-        public void sendSessionModifyResponse(VideoCallProfile responseProfile) {
-            mMessageHandler.obtainMessage(
-                    MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
-        }
-
-        public void requestCameraCapabilities() {
-            mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
-        }
-
-        public void requestCallDataUsage() {
-            mMessageHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget();
-        }
-
-        public void setPauseImage(String uri) {
-            mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
-        }
-    }
-
-    private final CallVideoProviderHandler mMessageHandler = new CallVideoProviderHandler();
-    private final CallVideoProviderBinder mBinder;
-
-    public CallVideoProvider() {
-        mBinder = new CallVideoProviderBinder();
-    }
-
-    /**
-     * Returns binder object which can be used across IPC methods.
-     * @hide
-     */
-    public final ICallVideoProvider getInterface() {
-        return mBinder;
-    }
-
-    /**
-     * Sets a remote interface for invoking callback methods in the InCallUI after performing
-     * telephony actions.
-     *
-     * @param callVideoClient The call video client.
-     */
-    public abstract void onSetCallVideoClient(RemoteCallVideoClient callVideoClient);
-
-    /**
-     * Sets the camera to be used for video recording in a video call.
-     *
-     * @param cameraId The id of the camera.
-     */
-    public abstract void onSetCamera(String cameraId);
-
-    /**
-     * Sets the surface to be used for displaying a preview of what the user's camera is
-     * currently capturing.  When video transmission is enabled, this is the video signal which is
-     * sent to the remote device.
-     *
-     * @param surface The surface.
-     */
-    public abstract void onSetPreviewSurface(Surface surface);
-
-    /**
-     * Sets the surface to be used for displaying the video received from the remote device.
-     *
-     * @param surface The surface.
-     */
-    public abstract void onSetDisplaySurface(Surface surface);
-
-    /**
-     * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of the
-     * device is 0 degrees.
-     *
-     * @param rotation The device orientation, in degrees.
-     */
-    public abstract void onSetDeviceOrientation(int rotation);
-
-    /**
-     * Sets camera zoom ratio.
-     *
-     * @param value The camera zoom ratio.
-     */
-    public abstract void onSetZoom(float value);
-
-    /**
-     * Issues a request to modify the properties of the current session.  The request is sent to
-     * the remote device where it it handled by
-     * {@link CallVideoClient#onReceiveSessionModifyRequest}.
-     * Some examples of session modification requests: upgrade call from audio to video, downgrade
-     * call from video to audio, pause video.
-     *
-     * @param requestProfile The requested call video properties.
-     */
-    public abstract void onSendSessionModifyRequest(VideoCallProfile requestProfile);
-
-    /**
-     * Provides a response to a request to change the current call session video
-     * properties.
-     * This is in response to a request the InCall UI has received via
-     * {@link CallVideoClient#onReceiveSessionModifyRequest}.
-     * The response is handled on the remove device by
-     * {@link CallVideoClient#onReceiveSessionModifyResponse}.
-     *
-     * @param responseProfile The response call video properties.
-     */
-    public abstract void onSendSessionModifyResponse(VideoCallProfile responseProfile);
-
-    /**
-     * Issues a request to the video provider to retrieve the camera capabilities.
-     * Camera capabilities are reported back to the caller via
-     * {@link CallVideoClient#onHandleCameraCapabilitiesChange(CallCameraCapabilities)}.
-     */
-    public abstract void onRequestCameraCapabilities();
-
-    /**
-     * Issues a request to the video telephony framework to retrieve the cumulative data usage for
-     * the current call.  Data usage is reported back to the caller via
-     * {@link CallVideoClient#onUpdateCallDataUsage}.
-     */
-    public abstract void onRequestCallDataUsage();
-
-    /**
-     * Provides the video telephony framework with the URI of an image to be displayed to remote
-     * devices when the video signal is paused.
-     *
-     * @param uri URI of image to display.
-     */
-    public abstract void onSetPauseImage(String uri);
-}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 02af68e..322dafe 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -19,10 +19,8 @@
 import android.app.PendingIntent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.telecomm.CallVideoProvider;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -46,21 +44,27 @@
         public void onDestroyed(Connection c) {}
         public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {}
         public void onParentConnectionChanged(Connection c, Connection parent) {}
-        public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) {}
+        public void onVideoCallProviderChanged(
+                Connection c, ConnectionService.VideoCallProvider videoCallProvider) {}
         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
         public void onStartActivityFromInCall(Connection c, PendingIntent intent) {}
+        public void onFailed(Connection c, int code, String msg) {}
     }
 
     public final class State {
         private State() {}
 
-        public static final int NEW = 0;
-        public static final int RINGING = 1;
-        public static final int DIALING = 2;
-        public static final int ACTIVE = 3;
-        public static final int HOLDING = 4;
-        public static final int DISCONNECTED = 5;
+        public static final int INITIALIZING = 0;
+        public static final int NEW = 1;
+        public static final int RINGING = 2;
+        public static final int DIALING = 3;
+        public static final int ACTIVE = 4;
+        public static final int HOLDING = 5;
+        public static final int DISCONNECTED = 6;
+        public static final int FAILED = 7;
+        public static final int CANCELED = 8;
+
     }
 
     private final Set<Listener> mListeners = new HashSet<>();
@@ -75,10 +79,13 @@
     private boolean mRequestingRingback = false;
     private int mCallCapabilities;
     private Connection mParentConnection;
-    private CallVideoProvider mCallVideoProvider;
+    private ConnectionService.VideoCallProvider mVideoCallProvider;
     private boolean mAudioModeIsVoip;
     private StatusHints mStatusHints;
     private int mVideoState;
+    private int mFailureCode;
+    private String mFailureMessage;
+    private boolean mIsCanceled;
 
     /**
      * Create a new Connection.
@@ -199,6 +206,20 @@
     }
 
     /**
+     * @return The failure code ({@see DisconnectCause}) associated with this failed connection.
+     */
+    public final int getFailureCode() {
+        return mFailureCode;
+    }
+
+    /**
+     * @return The reason for the connection failure. This will not be displayed to the user.
+     */
+    public final String getFailureMessage() {
+        return mFailureMessage;
+    }
+
+    /**
      * Inform this Connection that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
@@ -228,6 +249,10 @@
                 return "HOLDING";
             case State.DISCONNECTED:
                 return "DISCONNECTED";
+            case State.FAILED:
+                return "FAILED";
+            case State.CANCELED:
+                return "CANCELED";
             default:
                 Log.wtf(Connection.class, "Unknown state %d", state);
                 return "UNKNOWN";
@@ -302,6 +327,33 @@
     }
 
     /**
+     * Cancel the {@link Connection}. Once this is called, the {@link Connection} will not be used,
+     * and no subsequent {@link Connection}s will be attempted.
+     */
+    public final void setCanceled() {
+        Log.d(this, "setCanceled");
+        setState(State.CANCELED);
+    }
+
+    /**
+     * Move the {@link Connection} to the {@link State#FAILED} state, with the given code
+     * ({@see DisconnectCause}) and message. This message is not shown to the user, but is useful
+     * for logging and debugging purposes.
+     * <p>
+     * After calling this, the {@link Connection} will not be used.
+     *
+     * @param code The {@link android.telephony.DisconnectCause} indicating why the connection
+     *             failed.
+     * @param message A message explaining why the {@link Connection} failed.
+     */
+    public final void setFailed(int code, String message) {
+        Log.d(this, "setFailed (%d: %s)", code, message);
+        mFailureCode = code;
+        mFailureMessage = message;
+        setState(State.FAILED);
+    }
+
+    /**
      * Set the video state for the connection.
      * Valid values: {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY},
      * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL},
@@ -335,6 +387,20 @@
     }
 
     /**
+     * Sets state to initializing (this Connection is not yet ready to be used).
+     */
+    public final void setInitializing() {
+        setState(State.INITIALIZING);
+    }
+
+    /**
+     * Sets state to initialized (the Connection has been set up and is now ready to be used).
+     */
+    public final void setInitialized() {
+        setState(State.NEW);
+    }
+
+    /**
      * Sets state to dialing (e.g., dialing an outbound call).
      */
     public final void setDialing() {
@@ -349,18 +415,18 @@
     }
 
     /**
-     * Sets the call video provider.
-     * @param callVideoProvider The call video provider.
+     * Sets the video call provider.
+     * @param videoCallProvider The video call provider.
      */
-    public final void setCallVideoProvider(CallVideoProvider callVideoProvider) {
-        mCallVideoProvider = callVideoProvider;
+    public final void setVideoCallProvider(ConnectionService.VideoCallProvider videoCallProvider) {
+        mVideoCallProvider = videoCallProvider;
         for (Listener l : mListeners) {
-            l.onCallVideoProviderChanged(this, callVideoProvider);
+            l.onVideoCallProviderChanged(this, videoCallProvider);
         }
     }
 
-    public final CallVideoProvider getCallVideoProvider() {
-        return mCallVideoProvider;
+    public final ConnectionService.VideoCallProvider getVideoCallProvider() {
+        return mVideoCallProvider;
     }
 
     /**
@@ -487,8 +553,8 @@
     public void onSetAudioState(CallAudioState state) {}
 
     /**
-     * Notifies this Connection of an internal state change. This method is called before the
-     * state is actually changed.
+     * Notifies this Connection of an internal state change. This method is called after the
+     * state is changed.
      *
      * @param state The new state, a {@link Connection.State} member.
      */
@@ -579,11 +645,50 @@
     }
 
     private void setState(int state) {
-        Log.d(this, "setState: %s", stateToString(state));
-        this.mState = state;
-        for (Listener l : mListeners) {
-            l.onStateChanged(this, state);
+        if (mState == State.FAILED || mState == State.CANCELED) {
+            Log.d(this, "Connection already %s; cannot transition out of this state.",
+                    stateToString(mState));
+            return;
         }
-        onSetState(state);
+        if (mState != state) {
+            Log.d(this, "setState: %s", stateToString(state));
+            mState = state;
+            for (Listener l : mListeners) {
+                l.onStateChanged(this, state);
+            }
+            onSetState(state);
+        }
+    }
+
+    /**
+     * Return a {@link Connection} which represents a failed connection attempt. The returned
+     * {@link Connection} will have {@link #getFailureCode()}, {@link #getFailureMessage()}, and
+     * {@link #getState()} set appropriately, but the {@link Connection} itself should not be used
+     * for anything.
+     *
+     * @param code The failure code ({@see DisconnectCause}).
+     * @param message A reason for why the connection failed (not intended to be shown to the user).
+     * @return A {@link Connection} which indicates failure.
+     */
+    public static Connection getFailedConnection(final int code, final String message) {
+        return new Connection() {{
+            setFailed(code, message);
+        }};
+    }
+
+    private static final Connection CANCELED_CONNECTION = new Connection() {{
+        setCanceled();
+    }};
+
+    /**
+     * Return a {@link Connection} which represents a canceled a connection attempt. The returned
+     * {@link Connection} will have state {@link State#CANCELED}, and cannot be moved out of that
+     * state. This connection should not be used for anything, and no other {@link Connection}s
+     * should be attempted.
+     *
+     * @return A {@link Connection} which indicates that the underlying call should be canceled.
+     */
+    public static Connection getCanceledConnection() {
+        return CANCELED_CONNECTION;
     }
 }
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
index 4d945a3..020b692 100644
--- a/telecomm/java/android/telecomm/ConnectionRequest.java
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -20,6 +20,8 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ResultReceiver;
+import android.telephony.DisconnectCause;
 
 /**
  * Simple data container encapsulating a request to some entity to
@@ -110,6 +112,7 @@
         return mVideoState;
     }
 
+    @Override
     public String toString() {
         return String.format("PhoneConnectionRequest %s %s",
                 mHandle == null
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index d5b39cf..cefa929 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -28,10 +28,15 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.telephony.DisconnectCause;
+import android.os.RemoteException;
+import android.view.Surface;
 
 import com.android.internal.os.SomeArgs;
 import com.android.internal.telecomm.IConnectionService;
 import com.android.internal.telecomm.IConnectionServiceAdapter;
+import com.android.internal.telecomm.IVideoCallCallback;
+import com.android.internal.telecomm.IVideoCallProvider;
 import com.android.internal.telecomm.RemoteServiceCallback;
 
 import java.util.Collection;
@@ -132,7 +137,7 @@
         public void answer(String callId, int videoState) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = callId;
-            args.arg2 = videoState;
+            args.argi1 = videoState;
             mHandler.obtainMessage(MSG_ANSWER, args).sendToTarget();
         }
 
@@ -224,7 +229,7 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         String callId = (String) args.arg1;
-                        int videoState = (int) args.arg2;
+                        int videoState = args.argi1;
                         answer(callId, videoState);
                     } finally {
                         args.recycle();
@@ -390,9 +395,9 @@
         }
 
         @Override
-        public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) {
+        public void onVideoCallProviderChanged(Connection c, VideoCallProvider videoCallProvider) {
             String id = mIdByConnection.get(c);
-            mAdapter.setCallVideoProvider(id, callVideoProvider);
+            mAdapter.setVideoCallProvider(id, videoCallProvider);
         }
 
         @Override
@@ -425,48 +430,76 @@
      * incoming call. In either case, telecomm will cycle through a set of services and call
      * createConnection util a connection service cancels the process or completes it successfully.
      */
-    private void createConnection(ConnectionRequest originalRequest, boolean isIncoming) {
-        Log.d(this, "call %s", originalRequest);
-        CreateConnectionResponse response = new CreateConnectionResponse<Connection>() {
-            @Override
-            public void onSuccess(ConnectionRequest request, Connection connection) {
-                Log.d(this, "adapter handleCreateConnectionSuccessful %s",
-                        request.getCallId());
-                addConnection(request.getCallId(), connection);
-                mAdapter.handleCreateConnectionSuccessful(
-                        request,
-                        new ParcelableConnection(
-                                request.getAccountHandle(),
-                                connection.getState(),
-                                connection.getCallCapabilities(),
-                                connection.getHandle(),
-                                connection.getHandlePresentation(),
-                                connection.getCallerDisplayName(),
-                                connection.getCallerDisplayNamePresentation(),
-                                connection.getCallVideoProvider() == null ?
-                                        null : connection.getCallVideoProvider().getInterface(),
-                                connection.getVideoState()));
-            }
+    private void createConnection(final ConnectionRequest request, boolean isIncoming) {
+        Log.d(this, "call %s", request);
 
-            @Override
-            public void onFailure(ConnectionRequest request, int code, String msg) {
-                // Tell telecomm to try a different service.
-                mAdapter.handleCreateConnectionFailed(request, code, msg);
-            }
+        final Connection createdConnection;
+        if (isIncoming) {
+            createdConnection = onCreateIncomingConnection(request);
+        } else {
+            createdConnection = onCreateOutgoingConnection(request);
+        }
 
-            @Override
-            public void onCancel(ConnectionRequest request) {
+        if (createdConnection != null) {
+            Log.d(this, "adapter handleCreateConnectionSuccessful %s",
+                    request.getCallId());
+            if (createdConnection.getState() == Connection.State.INITIALIZING) {
+                // Wait for the connection to become initialized.
+                createdConnection.addConnectionListener(new Connection.Listener() {
+                    @Override
+                    public void onStateChanged(Connection c, int state) {
+                        switch (state) {
+                            case Connection.State.FAILED:
+                                Log.d(this, "Connection (%s) failed (%d: %s)", request,
+                                        c.getFailureCode(), c.getFailureMessage());
+                                mAdapter.handleCreateConnectionFailed(request, c.getFailureCode(),
+                                        c.getFailureMessage());
+                                break;
+                            case Connection.State.CANCELED:
+                                Log.d(this, "Connection (%s) canceled", request);
+                                mAdapter.handleCreateConnectionCancelled(request);
+                                break;
+                            case Connection.State.INITIALIZING:
+                                Log.d(this, "State changed to INITIALIZING; ignoring");
+                                return; // Don't want to stop listening on this state transition.
+                            default:
+                                Log.d(this, "Connection created in state %s",
+                                        Connection.stateToString(state));
+                                connectionCreated(request, createdConnection);
+                                break;
+                        }
+                        c.removeConnectionListener(this);
+                    }
+                });
+            } else if (createdConnection.getState() == Connection.State.CANCELED) {
                 // Tell telecomm not to attempt any more services.
                 mAdapter.handleCreateConnectionCancelled(request);
+            } else {
+                connectionCreated(request, createdConnection);
             }
-        };
-        if (isIncoming) {
-            onCreateIncomingConnection(originalRequest, response);
         } else {
-            onCreateOutgoingConnection(originalRequest, response);
+            // Tell telecomm to try a different service.
+            mAdapter.handleCreateConnectionFailed(request, DisconnectCause.ERROR_UNSPECIFIED, null);
         }
     }
 
+    private void connectionCreated(ConnectionRequest request, Connection connection) {
+        addConnection(request.getCallId(), connection);
+        mAdapter.handleCreateConnectionSuccessful(
+                request,
+                new ParcelableConnection(
+                        request.getAccountHandle(),
+                        connection.getState(),
+                        connection.getCallCapabilities(),
+                        connection.getHandle(),
+                        connection.getHandlePresentation(),
+                        connection.getCallerDisplayName(),
+                        connection.getCallerDisplayNamePresentation(),
+                        connection.getVideoCallProvider() == null ?
+                                null : connection.getVideoCallProvider().getInterface(),
+                        connection.getVideoState()));
+    }
+
     private void abort(String callId) {
         Log.d(this, "abort %s", callId);
         findConnectionForAction(callId, "abort").onAbort();
@@ -609,13 +642,6 @@
         });
     }
 
-    public final void lookupRemoteAccounts(
-            Uri handle, SimpleResponse<Uri, List<PhoneAccountHandle>> response) {
-        mAccountLookupResponse = response;
-        mAccountLookupHandle = handle;
-        maybeRespondToAccountLookup();
-    }
-
     public final void maybeRespondToAccountLookup() {
         if (mAreAccountsInitialized && mAccountLookupResponse != null) {
             mAccountLookupResponse.onResult(
@@ -627,16 +653,12 @@
         }
     }
 
-    public final void createRemoteIncomingConnection(
-            ConnectionRequest request,
-            CreateConnectionResponse<RemoteConnection> response) {
-        mRemoteConnectionManager.createRemoteConnection(request, response, true);
+    public final RemoteConnection createRemoteIncomingConnection(ConnectionRequest request) {
+        return mRemoteConnectionManager.createRemoteConnection(request, true);
     }
 
-    public final void createRemoteOutgoingConnection(
-            ConnectionRequest request,
-            CreateConnectionResponse<RemoteConnection> response) {
-        mRemoteConnectionManager.createRemoteConnection(request, response, false);
+    public final RemoteConnection createRemoteOutgoingConnection(ConnectionRequest request) {
+        return mRemoteConnectionManager.createRemoteConnection(request, false);
     }
 
     /**
@@ -649,23 +671,22 @@
     /**
      * Create a Connection given an incoming request. This is used to attach to existing incoming
      * calls.
-     *
      * @param request Details about the incoming call.
-     * @param callback A callback for providing the result.
+     *
+     * @return The {@link Connection} object to satisfy this call, or {@code null} to not handle
+     * the call.
      */
-    public void onCreateIncomingConnection(
-            ConnectionRequest request,
-            CreateConnectionResponse<Connection> callback) {}
+    public Connection onCreateIncomingConnection(ConnectionRequest request) { return null; }
 
     /**
      * Create a Connection given an outgoing request. This is used to initiate new outgoing calls.
+     *  @param request Details about the outgoing call.
      *
-     * @param request Details about the outgoing call.
-     * @param callback A callback for providing the result.
+     * @return The {@link Connection} object to satisfy this request,
+     * or null to not handle the call.
+     *
      */
-    public void onCreateOutgoingConnection(
-            ConnectionRequest request,
-            CreateConnectionResponse<Connection> callback) {}
+    public Connection onCreateOutgoingConnection(ConnectionRequest request) { return null; }
 
     /**
      * Returns a new or existing conference connection when the the user elects to convert the
@@ -742,4 +763,312 @@
         Log.w(this, "%s - Cannot find Connection %s", action, callId);
         return NULL_CONNECTION;
     }
+
+    public static abstract class VideoCallProvider {
+        private static final int MSG_SET_VIDEO_CALL_LISTENER = 1;
+        private static final int MSG_SET_CAMERA = 2;
+        private static final int MSG_SET_PREVIEW_SURFACE = 3;
+        private static final int MSG_SET_DISPLAY_SURFACE = 4;
+        private static final int MSG_SET_DEVICE_ORIENTATION = 5;
+        private static final int MSG_SET_ZOOM = 6;
+        private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
+        private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
+        private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
+        private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
+        private static final int MSG_SET_PAUSE_IMAGE = 11;
+
+        private final VideoCallProviderHandler mMessageHandler = new VideoCallProviderHandler();
+        private final VideoCallProviderBinder mBinder;
+        private IVideoCallCallback mVideoCallListener;
+
+        /**
+         * Default handler used to consolidate binder method calls onto a single thread.
+         */
+        private final class VideoCallProviderHandler extends Handler {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_SET_VIDEO_CALL_LISTENER:
+                        mVideoCallListener = IVideoCallCallback.Stub.asInterface((IBinder) msg.obj);
+                        break;
+                    case MSG_SET_CAMERA:
+                        onSetCamera((String) msg.obj);
+                        break;
+                    case MSG_SET_PREVIEW_SURFACE:
+                        onSetPreviewSurface((Surface) msg.obj);
+                        break;
+                    case MSG_SET_DISPLAY_SURFACE:
+                        onSetDisplaySurface((Surface) msg.obj);
+                        break;
+                    case MSG_SET_DEVICE_ORIENTATION:
+                        onSetDeviceOrientation(msg.arg1);
+                        break;
+                    case MSG_SET_ZOOM:
+                        onSetZoom((Float) msg.obj);
+                        break;
+                    case MSG_SEND_SESSION_MODIFY_REQUEST:
+                        onSendSessionModifyRequest((VideoCallProfile) msg.obj);
+                        break;
+                    case MSG_SEND_SESSION_MODIFY_RESPONSE:
+                        onSendSessionModifyResponse((VideoCallProfile) msg.obj);
+                        break;
+                    case MSG_REQUEST_CAMERA_CAPABILITIES:
+                        onRequestCameraCapabilities();
+                        break;
+                    case MSG_REQUEST_CALL_DATA_USAGE:
+                        onRequestCallDataUsage();
+                        break;
+                    case MSG_SET_PAUSE_IMAGE:
+                        onSetPauseImage((String) msg.obj);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        /**
+         * IVideoCallProvider stub implementation.
+         */
+        private final class VideoCallProviderBinder extends IVideoCallProvider.Stub {
+            public void setVideoCallListener(IBinder videoCallListenerBinder) {
+                mMessageHandler.obtainMessage(
+                        MSG_SET_VIDEO_CALL_LISTENER, videoCallListenerBinder).sendToTarget();
+            }
+
+            public void setCamera(String cameraId) {
+                mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
+            }
+
+            public void setPreviewSurface(Surface surface) {
+                mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
+            }
+
+            public void setDisplaySurface(Surface surface) {
+                mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
+            }
+
+            public void setDeviceOrientation(int rotation) {
+                mMessageHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation).sendToTarget();
+            }
+
+            public void setZoom(float value) {
+                mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
+            }
+
+            public void sendSessionModifyRequest(VideoCallProfile requestProfile) {
+                mMessageHandler.obtainMessage(
+                        MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget();
+            }
+
+            public void sendSessionModifyResponse(VideoCallProfile responseProfile) {
+                mMessageHandler.obtainMessage(
+                        MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
+            }
+
+            public void requestCameraCapabilities() {
+                mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
+            }
+
+            public void requestCallDataUsage() {
+                mMessageHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget();
+            }
+
+            public void setPauseImage(String uri) {
+                mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
+            }
+        }
+
+        public VideoCallProvider() {
+            mBinder = new VideoCallProviderBinder();
+        }
+
+        /**
+         * Returns binder object which can be used across IPC methods.
+         * @hide
+         */
+        public final IVideoCallProvider getInterface() {
+            return mBinder;
+        }
+
+        /**
+         * Sets the camera to be used for video recording in a video call.
+         *
+         * @param cameraId The id of the camera.
+         */
+        public abstract void onSetCamera(String cameraId);
+
+        /**
+         * Sets the surface to be used for displaying a preview of what the user's camera is
+         * currently capturing.  When video transmission is enabled, this is the video signal which is
+         * sent to the remote device.
+         *
+         * @param surface The surface.
+         */
+        public abstract void onSetPreviewSurface(Surface surface);
+
+        /**
+         * Sets the surface to be used for displaying the video received from the remote device.
+         *
+         * @param surface The surface.
+         */
+        public abstract void onSetDisplaySurface(Surface surface);
+
+        /**
+         * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of the
+         * device is 0 degrees.
+         *
+         * @param rotation The device orientation, in degrees.
+         */
+        public abstract void onSetDeviceOrientation(int rotation);
+
+        /**
+         * Sets camera zoom ratio.
+         *
+         * @param value The camera zoom ratio.
+         */
+        public abstract void onSetZoom(float value);
+
+        /**
+         * Issues a request to modify the properties of the current session.  The request is sent to
+         * the remote device where it it handled by
+         * {@link InCallService.VideoCall.Listener#onSessionModifyRequestReceived}.
+         * Some examples of session modification requests: upgrade call from audio to video, downgrade
+         * call from video to audio, pause video.
+         *
+         * @param requestProfile The requested call video properties.
+         */
+        public abstract void onSendSessionModifyRequest(VideoCallProfile requestProfile);
+
+        /**te
+         * Provides a response to a request to change the current call session video
+         * properties.
+         * This is in response to a request the InCall UI has received via
+         * {@link InCallService.VideoCall.Listener#onSessionModifyRequestReceived}.
+         * The response is handled on the remove device by
+         * {@link InCallService.VideoCall.Listener#onSessionModifyResponseReceived}.
+         *
+         * @param responseProfile The response call video properties.
+         */
+        public abstract void onSendSessionModifyResponse(VideoCallProfile responseProfile);
+
+        /**
+         * Issues a request to the video provider to retrieve the camera capabilities.
+         * Camera capabilities are reported back to the caller via
+         * {@link InCallService.VideoCall.Listener#onCameraCapabilitiesChanged(CallCameraCapabilities)}.
+         */
+        public abstract void onRequestCameraCapabilities();
+
+        /**
+         * Issues a request to the video telephony framework to retrieve the cumulative data usage for
+         * the current call.  Data usage is reported back to the caller via
+         * {@link InCallService.VideoCall.Listener#onCallDataUsageChanged}.
+         */
+        public abstract void onRequestCallDataUsage();
+
+        /**
+         * Provides the video telephony framework with the URI of an image to be displayed to remote
+         * devices when the video signal is paused.
+         *
+         * @param uri URI of image to display.
+         */
+        public abstract void onSetPauseImage(String uri);
+
+        /**
+         * Invokes callback method defined in {@link InCallService.VideoCall.Listener}.
+         *
+         * @param videoCallProfile The requested video call profile.
+         */
+        public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
+            if (mVideoCallListener != null) {
+                try {
+                    mVideoCallListener.receiveSessionModifyRequest(videoCallProfile);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+
+        /**
+         * Invokes callback method defined in {@link InCallService.VideoCall.Listener}.
+         *
+         * @param status Status of the session modify request.  Valid values are
+         *               {@link InCallService.VideoCall#SESSION_MODIFY_REQUEST_SUCCESS},
+         *               {@link InCallService.VideoCall#SESSION_MODIFY_REQUEST_FAIL},
+         *               {@link InCallService.VideoCall#SESSION_MODIFY_REQUEST_INVALID}
+         * @param requestedProfile The original request which was sent to the remote device.
+         * @param responseProfile The actual profile changes made by the remote device.
+         */
+        public void receiveSessionModifyResponse(int status,
+                                                 VideoCallProfile requestedProfile, VideoCallProfile responseProfile) {
+            if (mVideoCallListener != null) {
+                try {
+                    mVideoCallListener.receiveSessionModifyResponse(
+                            status, requestedProfile, responseProfile);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+
+        /**
+         * Invokes callback method defined in {@link InCallService.VideoCall.Listener}.
+         *
+         * Valid values are: {@link InCallService.VideoCall#SESSION_EVENT_RX_PAUSE},
+         * {@link InCallService.VideoCall#SESSION_EVENT_RX_RESUME},
+         * {@link InCallService.VideoCall#SESSION_EVENT_TX_START},
+         * {@link InCallService.VideoCall#SESSION_EVENT_TX_STOP}
+         *
+         * @param event The event.
+         */
+        public void handleCallSessionEvent(int event) {
+            if (mVideoCallListener != null) {
+                try {
+                    mVideoCallListener.handleCallSessionEvent(event);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+
+        /**
+         * Invokes callback method defined in {@link InCallService.VideoCall.Listener}.
+         *
+         * @param width  The updated peer video width.
+         * @param height The updated peer video height.
+         */
+        public void changePeerDimensions(int width, int height) {
+            if (mVideoCallListener != null) {
+                try {
+                    mVideoCallListener.changePeerDimensions(width, height);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+
+        /**
+         * Invokes callback method defined in {@link InCallService.VideoCall.Listener}.
+         *
+         * @param dataUsage The updated data usage.
+         */
+        public void changeCallDataUsage(int dataUsage) {
+            if (mVideoCallListener != null) {
+                try {
+                    mVideoCallListener.changeCallDataUsage(dataUsage);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+
+        /**
+         * Invokes callback method defined in {@link InCallService.VideoCall.Listener}.
+         *
+         * @param callCameraCapabilities The changed camera capabilities.
+         */
+        public void changeCameraCapabilities(CallCameraCapabilities callCameraCapabilities) {
+            if (mVideoCallListener != null) {
+                try {
+                    mVideoCallListener.changeCameraCapabilities(callCameraCapabilities);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+    }
 }
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index 66e9925..ea61362 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -25,7 +25,7 @@
 
 import com.android.internal.telecomm.IConnectionService;
 import com.android.internal.telecomm.IConnectionServiceAdapter;
-import com.android.internal.telecomm.ICallVideoProvider;
+import com.android.internal.telecomm.IVideoCallProvider;
 import com.android.internal.telecomm.RemoteServiceCallback;
 
 import java.util.ArrayList;
@@ -273,14 +273,15 @@
      * Sets the call video provider for a call.
      *
      * @param callId The unique ID of the call to set with the given call video provider.
-     * @param callVideoProvider The call video provider instance to set on the call.
+     * @param videoCallProvider The call video provider instance to set on the call.
      */
-    void setCallVideoProvider(String callId, CallVideoProvider callVideoProvider) {
+    void setVideoCallProvider(
+            String callId, ConnectionService.VideoCallProvider videoCallProvider) {
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
-                adapter.setCallVideoProvider(
+                adapter.setVideoCallProvider(
                         callId,
-                        callVideoProvider == null ? null : callVideoProvider.getInterface());
+                        videoCallProvider == null ? null : videoCallProvider.getInterface());
             } catch (RemoteException e) {
             }
         }
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
index 9699e2a..14b25dc8 100644
--- a/telecomm/java/android/telecomm/InCallService.java
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -23,11 +23,14 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.view.Surface;
 
 import com.android.internal.os.SomeArgs;
 import com.android.internal.telecomm.IInCallAdapter;
 import com.android.internal.telecomm.IInCallService;
 
+import java.lang.String;
+
 /**
  * This service is implemented by any app that wishes to provide the user-interface for managing
  * phone calls. Telecomm binds to this service while there exists a live (active or incoming) call,
@@ -196,4 +199,210 @@
      */
     public void onPhoneDestroyed(Phone phone) {
     }
+
+    /**
+     * Class to invoke functionality related to video calls.
+     */
+    public static abstract class VideoCall {
+
+        /**
+         * Video is not being received (no protocol pause was issued).
+         */
+        public static final int SESSION_EVENT_RX_PAUSE = 1;
+
+        /**
+         * Video reception has resumed after a SESSION_EVENT_RX_PAUSE.
+         */
+        public static final int SESSION_EVENT_RX_RESUME = 2;
+
+        /**
+         * Video transmission has begun. This occurs after a negotiated start of video transmission
+         * when the underlying protocol has actually begun transmitting video to the remote party.
+         */
+        public static final int SESSION_EVENT_TX_START = 3;
+
+        /**
+         * Video transmission has stopped. This occur after a negotiated stop of video transmission when
+         * the underlying protocol has actually stopped transmitting video to the remote party.
+         */
+        public static final int SESSION_EVENT_TX_STOP = 4;
+
+        /**
+         * Session modify request was successful.
+         */
+        public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
+
+        /**
+         * Session modify request failed.
+         */
+        public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
+
+        /**
+         * Session modify request ignored due to invalid parameters.
+         */
+        public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
+
+        /**
+         * Sets a listener to invoke callback methods in the InCallUI after performing video
+         * telephony actions.
+         *
+         * @param videoCallListener The call video client.
+         */
+        public abstract void setVideoCallListener(VideoCall.Listener videoCallListener);
+
+        /**
+         * Sets the camera to be used for video recording in a video call.
+         *
+         * @param cameraId The id of the camera.
+         */
+        public abstract void setCamera(String cameraId);
+
+        /**
+         * Sets the surface to be used for displaying a preview of what the user's camera is
+         * currently capturing.  When video transmission is enabled, this is the video signal which
+         * is sent to the remote device.
+         *
+         * @param surface The surface.
+         */
+        public abstract void setPreviewSurface(Surface surface);
+
+        /**
+         * Sets the surface to be used for displaying the video received from the remote device.
+         *
+         * @param surface The surface.
+         */
+        public abstract void setDisplaySurface(Surface surface);
+
+        /**
+         * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of
+         * the device is 0 degrees.
+         *
+         * @param rotation The device orientation, in degrees.
+         */
+        public abstract void setDeviceOrientation(int rotation);
+
+        /**
+         * Sets camera zoom ratio.
+         *
+         * @param value The camera zoom ratio.
+         */
+        public abstract void setZoom(float value);
+
+        /**
+         * Issues a request to modify the properties of the current session.  The request is sent to
+         * the remote device where it it handled by
+         * {@link VideoCall.Listener#onSessionModifyRequestReceived}.
+         * Some examples of session modification requests: upgrade call from audio to video,
+         * downgrade call from video to audio, pause video.
+         *
+         * @param requestProfile The requested call video properties.
+         */
+        public abstract void sendSessionModifyRequest(VideoCallProfile requestProfile);
+
+        /**
+         * Provides a response to a request to change the current call session video
+         * properties.
+         * This is in response to a request the InCall UI has received via
+         * {@link VideoCall.Listener#onSessionModifyRequestReceived}.
+         * The response is handled on the remove device by
+         * {@link VideoCall.Listener#onSessionModifyResponseReceived}.
+         *
+         * @param responseProfile The response call video properties.
+         */
+        public abstract void sendSessionModifyResponse(VideoCallProfile responseProfile);
+
+        /**
+         * Issues a request to the video provider to retrieve the camera capabilities.
+         * Camera capabilities are reported back to the caller via
+         * {@link VideoCall.Listener#onCameraCapabilitiesChanged(CallCameraCapabilities)}.
+         */
+        public abstract void requestCameraCapabilities();
+
+        /**
+         * Issues a request to the video telephony framework to retrieve the cumulative data usage for
+         * the current call.  Data usage is reported back to the caller via
+         * {@link VideoCall.Listener#onCallDataUsageChanged}.
+         */
+        public abstract void requestCallDataUsage();
+
+        /**
+         * Provides the video telephony framework with the URI of an image to be displayed to remote
+         * devices when the video signal is paused.
+         *
+         * @param uri URI of image to display.
+         */
+        public abstract void setPauseImage(String uri);
+
+        /**
+         * Listener class which invokes callbacks after video call actions occur.
+         */
+        public static abstract class Listener {
+            /**
+             * Called when a session modification request is received from the remote device.
+             * The remote request is sent via
+             * {@link ConnectionService.VideoCallProvider#onSendSessionModifyRequest}. The InCall UI
+             * is responsible for potentially prompting the user whether they wish to accept the new
+             * call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a
+             * video call) and should call
+             * {@link ConnectionService.VideoCallProvider#onSendSessionModifyResponse} to indicate
+             * the video settings the user has agreed to.
+             *
+             * @param videoCallProfile The requested video call profile.
+             */
+            public abstract void onSessionModifyRequestReceived(VideoCallProfile videoCallProfile);
+
+            /**
+             * Called when a response to a session modification request is received from the remote
+             * device. The remote InCall UI sends the response using
+             * {@link ConnectionService.VideoCallProvider#onSendSessionModifyResponse}.
+             *
+             * @param status Status of the session modify request.  Valid values are
+             *               {@link VideoCall#SESSION_MODIFY_REQUEST_SUCCESS},
+             *               {@link VideoCall#SESSION_MODIFY_REQUEST_FAIL},
+             *               {@link VideoCall#SESSION_MODIFY_REQUEST_INVALID}
+             * @param requestedProfile The original request which was sent to the remote device.
+             * @param responseProfile The actual profile changes made by the remote device.
+             */
+            public abstract void onSessionModifyResponseReceived(int status,
+                    VideoCallProfile requestedProfile, VideoCallProfile responseProfile);
+
+            /**
+             * Handles events related to the current session which the client may wish to handle.
+             * These are separate from requested changes to the session due to the underlying
+             * protocol or connection.
+             *
+             * Valid values are: {@link VideoCall#SESSION_EVENT_RX_PAUSE},
+             * {@link VideoCall#SESSION_EVENT_RX_RESUME},
+             * {@link VideoCall#SESSION_EVENT_TX_START},
+             * {@link VideoCall#SESSION_EVENT_TX_STOP}
+             *
+             * @param event The event.
+             */
+            public abstract void onCallSessionEvent(int event);
+
+            /**
+             * Handles a change to the video dimensions from the remote caller (peer). This could
+             * happen if, for example, the peer changes orientation of their device.
+             *
+             * @param width  The updated peer video width.
+             * @param height The updated peer video height.
+             */
+            public abstract void onPeerDimensionsChanged(int width, int height);
+
+            /**
+             * Handles an update to the total data used for the current session.
+             *
+             * @param dataUsage The updated data usage.
+             */
+            public abstract void onCallDataUsageChanged(int dataUsage);
+
+            /**
+             * Handles a change in camera capabilities.
+             *
+             * @param callCameraCapabilities The changed camera capabilities.
+             */
+            public abstract void onCameraCapabilitiesChanged(
+                    CallCameraCapabilities callCameraCapabilities);
+        }
+    }
 }
diff --git a/telecomm/java/android/telecomm/ParcelableCall.java b/telecomm/java/android/telecomm/ParcelableCall.java
index 27a5c1d..e60761a 100644
--- a/telecomm/java/android/telecomm/ParcelableCall.java
+++ b/telecomm/java/android/telecomm/ParcelableCall.java
@@ -22,7 +22,7 @@
 import android.os.RemoteException;
 import android.telephony.DisconnectCause;
 
-import com.android.internal.telecomm.ICallVideoProvider;
+import com.android.internal.telecomm.IVideoCallProvider;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -45,8 +45,8 @@
     private final int mCallerDisplayNamePresentation;
     private final GatewayInfo mGatewayInfo;
     private final PhoneAccountHandle mAccountHandle;
-    private final ICallVideoProvider mCallVideoProvider;
-    private RemoteCallVideoProvider mRemoteCallVideoProvider;
+    private final IVideoCallProvider mVideoCallProvider;
+    private InCallService.VideoCall mVideoCall;
     private final String mParentCallId;
     private final List<String> mChildCallIds;
     private final StatusHints mStatusHints;
@@ -67,7 +67,7 @@
             int callerDisplayNamePresentation,
             GatewayInfo gatewayInfo,
             PhoneAccountHandle accountHandle,
-            ICallVideoProvider callVideoProvider,
+            IVideoCallProvider videoCallProvider,
             String parentCallId,
             List<String> childCallIds,
             StatusHints statusHints,
@@ -85,7 +85,7 @@
         mCallerDisplayNamePresentation = callerDisplayNamePresentation;
         mGatewayInfo = gatewayInfo;
         mAccountHandle = accountHandle;
-        mCallVideoProvider = callVideoProvider;
+        mVideoCallProvider = videoCallProvider;
         mParentCallId = parentCallId;
         mChildCallIds = childCallIds;
         mStatusHints = statusHints;
@@ -166,19 +166,19 @@
     }
 
     /**
-     * Returns an object for remotely communicating through the call video provider's binder.
-     * @return The call video provider.
+     * Returns an object for remotely communicating through the video call provider's binder.
+     * @return The video call.
      */
-    public RemoteCallVideoProvider getCallVideoProvider() throws RemoteException {
-        if (mRemoteCallVideoProvider == null && mCallVideoProvider != null) {
+    public InCallService.VideoCall getVideoCall() {
+        if (mVideoCall == null && mVideoCallProvider != null) {
             try {
-                mRemoteCallVideoProvider = new RemoteCallVideoProvider(mCallVideoProvider);
+                mVideoCall = new VideoCallImpl(mVideoCallProvider);
             } catch (RemoteException ignored) {
                 // Ignore RemoteException.
             }
         }
 
-        return mRemoteCallVideoProvider;
+        return mVideoCall;
     }
 
     /**
@@ -235,8 +235,8 @@
             int callerDisplayNamePresentation = source.readInt();
             GatewayInfo gatewayInfo = source.readParcelable(classLoader);
             PhoneAccountHandle accountHandle = source.readParcelable(classLoader);
-            ICallVideoProvider callVideoProvider =
-                    ICallVideoProvider.Stub.asInterface(source.readStrongBinder());
+            IVideoCallProvider videoCallProvider =
+                    IVideoCallProvider.Stub.asInterface(source.readStrongBinder());
             String parentCallId = source.readString();
             List<String> childCallIds = new ArrayList<>();
             source.readList(childCallIds, classLoader);
@@ -245,7 +245,7 @@
             return new ParcelableCall(id, state, disconnectCauseCode, disconnectCauseMsg,
                     cannedSmsResponses, capabilities, connectTimeMillis, handle, handlePresentation,
                     callerDisplayName, callerDisplayNamePresentation, gatewayInfo,
-                    accountHandle, callVideoProvider, parentCallId, childCallIds, statusHints,
+                    accountHandle, videoCallProvider, parentCallId, childCallIds, statusHints,
                     videoState);
         }
 
@@ -278,7 +278,7 @@
         destination.writeParcelable(mGatewayInfo, 0);
         destination.writeParcelable(mAccountHandle, 0);
         destination.writeStrongBinder(
-                mCallVideoProvider != null ? mCallVideoProvider.asBinder() : null);
+                mVideoCallProvider != null ? mVideoCallProvider.asBinder() : null);
         destination.writeString(mParentCallId);
         destination.writeList(mChildCallIds);
         destination.writeParcelable(mStatusHints, 0);
diff --git a/telecomm/java/android/telecomm/ParcelableConnection.java b/telecomm/java/android/telecomm/ParcelableConnection.java
index f730fef..e0bfab6 100644
--- a/telecomm/java/android/telecomm/ParcelableConnection.java
+++ b/telecomm/java/android/telecomm/ParcelableConnection.java
@@ -20,7 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.telecomm.ICallVideoProvider;
+import com.android.internal.telecomm.IVideoCallProvider;
 
 /**
  * Information about a connection that is used between Telecomm and the ConnectionService.
@@ -36,7 +36,7 @@
     private int mHandlePresentation;
     private String mCallerDisplayName;
     private int mCallerDisplayNamePresentation;
-    private ICallVideoProvider mCallVideoProvider;
+    private IVideoCallProvider mVideoCallProvider;
     private int mVideoState;
 
     /** @hide */
@@ -48,7 +48,7 @@
             int handlePresentation,
             String callerDisplayName,
             int callerDisplayNamePresentation,
-            ICallVideoProvider callVideoProvider,
+            IVideoCallProvider videoCallProvider,
             int videoState) {
         mPhoneAccount = phoneAccount;
         mState = state;
@@ -57,7 +57,7 @@
         mHandlePresentation = handlePresentation;
         mCallerDisplayName = callerDisplayName;
         mCallerDisplayNamePresentation = callerDisplayNamePresentation;
-        mCallVideoProvider = callVideoProvider;
+        mVideoCallProvider = videoCallProvider;
         mVideoState = videoState;
     }
 
@@ -90,8 +90,8 @@
         return mCallerDisplayNamePresentation;
     }
 
-    public ICallVideoProvider getCallVideoProvider() {
-        return mCallVideoProvider;
+    public IVideoCallProvider getVideoCallProvider() {
+        return mVideoCallProvider;
     }
 
     public int getVideoState() {
@@ -111,8 +111,8 @@
             int handlePresentation = source.readInt();
             String callerDisplayName = source.readString();
             int callerDisplayNamePresentation = source.readInt();
-            ICallVideoProvider callVideoProvider =
-                    ICallVideoProvider.Stub.asInterface(source.readStrongBinder());
+            IVideoCallProvider videoCallProvider =
+                    IVideoCallProvider.Stub.asInterface(source.readStrongBinder());
             int videoState = source.readInt();
 
             return new ParcelableConnection(
@@ -123,7 +123,7 @@
                     handlePresentation,
                     callerDisplayName,
                     callerDisplayNamePresentation,
-                    callVideoProvider,
+                    videoCallProvider,
                     videoState);
         }
 
@@ -150,7 +150,7 @@
         destination.writeString(mCallerDisplayName);
         destination.writeInt(mCallerDisplayNamePresentation);
         destination.writeStrongBinder(
-                mCallVideoProvider != null ? mCallVideoProvider.asBinder() : null);
+                mVideoCallProvider != null ? mVideoCallProvider.asBinder() : null);
         destination.writeInt(mVideoState);
     }
 }
diff --git a/telecomm/java/android/telecomm/RemoteCallVideoClient.java b/telecomm/java/android/telecomm/RemoteCallVideoClient.java
deleted file mode 100644
index 08d1391..0000000
--- a/telecomm/java/android/telecomm/RemoteCallVideoClient.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telecomm;
-
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.telecomm.CallCameraCapabilities;
-import android.telecomm.VideoCallProfile;
-
-import com.android.internal.telecomm.ICallVideoClient;
-
-/**
- * Remote class to invoke callbacks in InCallUI related to supporting video in calls.
- */
-public class RemoteCallVideoClient {
-    private final ICallVideoClient mCallVideoClient;
-
-    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
-        @Override
-        public void binderDied() {
-            mCallVideoClient.asBinder().unlinkToDeath(this, 0);
-        }
-    };
-
-    /** {@hide} */
-    RemoteCallVideoClient(ICallVideoClient callVideoProvider) throws RemoteException {
-        mCallVideoClient = callVideoProvider;
-        mCallVideoClient.asBinder().linkToDeath(mDeathRecipient, 0);
-    }
-
-    /**
-     * Called when a session modification request is received from the remote device.
-     * The remote request is sent via {@link CallVideoProvider#onSendSessionModifyRequest}.
-     * The InCall UI is responsible for potentially prompting the user whether they wish to accept
-     * the new call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a
-     * video call) and should call {@link CallVideoProvider#onSendSessionModifyResponse} to indicate
-     * the video settings the user has agreed to.
-     *
-     * @param videoCallProfile The requested video call profile.
-     */
-    public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
-        try {
-            mCallVideoClient.receiveSessionModifyRequest(videoCallProfile);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Called when a response to a session modification request is received from the remote device.
-     * The remote InCall UI sends the response using
-     * {@link CallVideoProvider#onSendSessionModifyResponse}.
-     *
-     * @param status Status of the session modify request.  Valid values are
-     *               {@link CallVideoClient#SESSION_MODIFY_REQUEST_SUCCESS},
-     *               {@link CallVideoClient#SESSION_MODIFY_REQUEST_FAIL},
-     *               {@link CallVideoClient#SESSION_MODIFY_REQUEST_INVALID}
-     * @param requestedProfile The original request which was sent to the remote device.
-     * @param responseProfile The actual profile changes made by the remote device.
-     */
-    public void receiveSessionModifyResponse(
-            int status, VideoCallProfile requestedProfile, VideoCallProfile responseProfile) {
-        try {
-            mCallVideoClient.receiveSessionModifyResponse(
-                    status, requestedProfile, responseProfile);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Handles events related to the current session which the client may wish to handle.  These
-     * are separate from requested changes to the session due to the underlying protocol or
-     * connection.
-     * Valid values are: {@link CallVideoClient#SESSION_EVENT_RX_PAUSE},
-     * {@link CallVideoClient#SESSION_EVENT_RX_RESUME},
-     * {@link CallVideoClient#SESSION_EVENT_TX_START}, {@link CallVideoClient#SESSION_EVENT_TX_STOP}
-     *
-     * @param event The event.
-     */
-    public void handleCallSessionEvent(int event) {
-        try {
-            mCallVideoClient.handleCallSessionEvent(event);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Handles a change to the video dimensions from the remote caller (peer).  This could happen
-     * if, for example, the peer changes orientation of their device.
-     *
-     * @param width  The updated peer video width.
-     * @param height The updated peer video height.
-     */
-    public void updatePeerDimensions(int width, int height) {
-        try {
-            mCallVideoClient.updatePeerDimensions(width, height);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Handles an update to the total data used for the current session.
-     *
-     * @param dataUsage The updated data usage.
-     */
-    public void updateCallDataUsage(int dataUsage) {
-        try {
-            mCallVideoClient.updateCallDataUsage(dataUsage);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Handles a change in camera capabilities.
-     *
-     * @param callCameraCapabilities The changed camera capabilities.
-     */
-    public void handleCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities) {
-        try {
-            mCallVideoClient.handleCameraCapabilitiesChange(callCameraCapabilities);
-        } catch (RemoteException e) {
-        }
-    }
-}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
deleted file mode 100644
index b8b8b9d..0000000
--- a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telecomm;
-
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.view.Surface;
-
-import com.android.internal.telecomm.ICallVideoProvider;
-
-/**
- * Remote class for InCallUI to invoke functionality provided for video in calls.
- */
-public class RemoteCallVideoProvider {
-    private final ICallVideoProvider mCallVideoProvider;
-
-    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
-        @Override
-        public void binderDied() {
-            mCallVideoProvider.asBinder().unlinkToDeath(this, 0);
-        }
-    };
-
-    /** {@hide} */
-    RemoteCallVideoProvider(ICallVideoProvider callVideoProvider) throws RemoteException {
-        mCallVideoProvider = callVideoProvider;
-        mCallVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
-    }
-
-    /**
-     * Sets a remote interface for invoking callback methods in the InCallUI after performing
-     * telephony actions.
-     *
-     * @param callVideoClient The call video client.
-     */
-    public void setCallVideoClient(CallVideoClient callVideoClient) {
-        try {
-            mCallVideoProvider.setCallVideoClient(callVideoClient.getBinder());
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Sets the camera to be used for video recording in a video call.
-     *
-     * @param cameraId The id of the camera.
-     */
-    public void setCamera(String cameraId) {
-        try {
-            mCallVideoProvider.setCamera(cameraId);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Sets the surface to be used for displaying a preview of what the user's camera is
-     * currently capturing.  When video transmission is enabled, this is the video signal which is
-     * sent to the remote device.
-     *
-     * @param surface The surface.
-     */
-    public void setPreviewSurface(Surface surface) {
-        try {
-            mCallVideoProvider.setPreviewSurface(surface);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Sets the surface to be used for displaying the video received from the remote device.
-     *
-     * @param surface The surface.
-     */
-    public void setDisplaySurface(Surface surface) {
-        try {
-            mCallVideoProvider.setDisplaySurface(surface);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of the
-     * device is 0 degrees.
-     *
-     * @param rotation The device orientation, in degrees.
-     */
-    public void setDeviceOrientation(int rotation) {
-        try {
-            mCallVideoProvider.setDeviceOrientation(rotation);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Sets camera zoom ratio.
-     *
-     * @param value The camera zoom ratio.
-     */
-    public void setZoom(float value) {
-        try {
-            mCallVideoProvider.setZoom(value);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Issues a request to modify the properties of the current session.  The request is sent to
-     * the remote device where it it handled by
-     * {@link CallVideoClient#onReceiveSessionModifyRequest}.
-     * Some examples of session modification requests: upgrade call from audio to video, downgrade
-     * call from video to audio, pause video.
-     *
-     * @param requestProfile The requested call video properties.
-     */
-    public void sendSessionModifyRequest(VideoCallProfile requestProfile) {
-        try {
-            mCallVideoProvider.sendSessionModifyRequest(requestProfile);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Provides a response to a request to change the current call session video
-     * properties.
-     * This is in response to a request the InCall UI has received via
-     * {@link CallVideoClient#onReceiveSessionModifyRequest}.
-     * The response is handled on the remove device by
-     * {@link CallVideoClient#onReceiveSessionModifyResponse}.
-     *
-     * @param responseProfile The response call video properties.
-     */
-    public void sendSessionModifyResponse(VideoCallProfile responseProfile) {
-        try {
-            mCallVideoProvider.sendSessionModifyResponse(responseProfile);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Issues a request to the video provider to retrieve the camera capabilities.
-     * Camera capabilities are reported back to the caller via
-     * {@link CallVideoClient#onHandleCameraCapabilitiesChange(CallCameraCapabilities)}.
-     */
-    public void requestCameraCapabilities() {
-        try {
-            mCallVideoProvider.requestCameraCapabilities();
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Issues a request to the video telephony framework to retrieve the cumulative data usage for
-     * the current call.  Data usage is reported back to the caller via
-     * {@link CallVideoClient#onUpdateCallDataUsage}.
-     */
-    public void requestCallDataUsage() {
-        try {
-            mCallVideoProvider.requestCallDataUsage();
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Provides the video telephony framework with the URI of an image to be displayed to remote
-     * devices when the video signal is paused.
-     *
-     * @param uri URI of image to display.
-     */
-    public void setPauseImage(String uri) {
-        try {
-            mCallVideoProvider.setPauseImage(uri);
-        } catch (RemoteException e) {
-        }
-    }
-}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/RemoteConnection.java b/telecomm/java/android/telecomm/RemoteConnection.java
index ddad58f..ab980e8 100644
--- a/telecomm/java/android/telecomm/RemoteConnection.java
+++ b/telecomm/java/android/telecomm/RemoteConnection.java
@@ -18,7 +18,6 @@
 
 import android.app.PendingIntent;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.RemoteException;
 import android.telephony.DisconnectCause;
 
@@ -31,23 +30,23 @@
  * RemoteConnection object used by RemoteConnectionService.
  */
 public final class RemoteConnection {
-    public interface Listener {
-        void onStateChanged(RemoteConnection connection, int state);
-        void onDisconnected(RemoteConnection connection, int cause, String message);
-        void onRequestingRingback(RemoteConnection connection, boolean ringback);
-        void onCallCapabilitiesChanged(RemoteConnection connection, int callCapabilities);
-        void onPostDialWait(RemoteConnection connection, String remainingDigits);
-        void onAudioModeIsVoipChanged(RemoteConnection connection, boolean isVoip);
-        void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints);
-        void onHandleChanged(RemoteConnection connection, Uri handle, int presentation);
-        void onCallerDisplayNameChanged(
-                RemoteConnection connection, String callerDisplayName, int presentation);
-        void onVideoStateChanged(RemoteConnection connection, int videoState);
-        void onStartActivityFromInCall(RemoteConnection connection, PendingIntent intent);
-        void onDestroyed(RemoteConnection connection);
+    public static abstract class Listener {
+        public void onStateChanged(RemoteConnection connection, int state) {}
+        public void onDisconnected(RemoteConnection connection, int cause, String message) {}
+        public void onRequestingRingback(RemoteConnection connection, boolean ringback) {}
+        public void onCallCapabilitiesChanged(RemoteConnection connection, int callCapabilities) {}
+        public void onPostDialWait(RemoteConnection connection, String remainingDigits) {}
+        public void onAudioModeIsVoipChanged(RemoteConnection connection, boolean isVoip) {}
+        public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {}
+        public void onHandleChanged(RemoteConnection connection, Uri handle, int presentation) {}
+        public void onCallerDisplayNameChanged(
+                RemoteConnection connection, String callerDisplayName, int presentation) {}
+        public void onVideoStateChanged(RemoteConnection connection, int videoState) {}
+        public void onStartActivityFromInCall(RemoteConnection connection, PendingIntent intent) {}
+        public void onDestroyed(RemoteConnection connection) {}
     }
 
-    private final IConnectionService mConnectionService;
+    private IConnectionService mConnectionService;
     private final String mConnectionId;
     private final Set<Listener> mListeners = new HashSet<>();
 
@@ -64,15 +63,35 @@
     private int mHandlePresentation;
     private String mCallerDisplayName;
     private int mCallerDisplayNamePresentation;
+    private int mFailureCode;
+    private String mFailureMessage;
 
     /**
      * @hide
      */
-    RemoteConnection(IConnectionService connectionService, String connectionId) {
+    RemoteConnection(IConnectionService connectionService, ConnectionRequest request,
+            boolean isIncoming) {
         mConnectionService = connectionService;
-        mConnectionId = connectionId;
+        mConnectionId = request.getCallId();
 
         mConnected = true;
+        mState = Connection.State.INITIALIZING;
+    }
+
+    /**
+     * Create a RemoteConnection which is used for failed connections. Note that using it for any
+     * "real" purpose will almost certainly fail. Callers should note the failure and act
+     * accordingly (moving on to another RemoteConnection, for example)
+     *
+     * @param failureCode
+     * @param failureMessage
+     */
+    private RemoteConnection(int failureCode, String failureMessage) {
+        this(null, null, true);
+        mConnected = false;
+        mState = Connection.State.FAILED;
+        mFailureCode = failureCode;
+        mFailureMessage = failureMessage;
     }
 
     public void addListener(Listener listener) {
@@ -127,6 +146,14 @@
         return mVideoState;
     }
 
+    public int getFailureCode() {
+        return mFailureCode;
+    }
+
+    public String getFailureMessage() {
+        return mFailureMessage;
+    }
+
     public void abort() {
         try {
             if (mConnected) {
@@ -354,4 +381,24 @@
             l.onStartActivityFromInCall(this, intent);
         }
     }
+
+    /** @hide */
+    void setConnectionService(IConnectionService connectionService) {
+        mConnectionService = connectionService;
+        mConnectionService = null;
+        setState(Connection.State.NEW);
+    }
+
+    /**
+     * Create a RemoteConnection which is in the {@link Connection.State#FAILED} state. Attempting
+     * to use it for anything will almost certainly result in bad things happening. Do not do this.
+     *
+     * @return a failed {@link RemoteConnection}
+     *
+     * @hide
+     *
+     */
+    public static RemoteConnection failure(int failureCode, String failureMessage) {
+        return new RemoteConnection(failureCode, failureMessage);
+    }
 }
diff --git a/telecomm/java/android/telecomm/RemoteConnectionManager.java b/telecomm/java/android/telecomm/RemoteConnectionManager.java
index b2d3dc7..3ca68a2 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionManager.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionManager.java
@@ -46,17 +46,11 @@
 
     List<PhoneAccountHandle> getAccounts(Uri handle) {
         List<PhoneAccountHandle> accountHandles = new LinkedList<>();
-        Log.d(this, "Getting accountHandles: " + mRemoteConnectionServices.keySet());
-        for (RemoteConnectionService remoteService : mRemoteConnectionServices.values()) {
-            // TODO(santoscordon): Eventually this will be async.
-            accountHandles.addAll(remoteService.lookupAccounts(handle));
-        }
         return accountHandles;
     }
 
-    public void createRemoteConnection(
+    public RemoteConnection createRemoteConnection(
             ConnectionRequest request,
-            ConnectionService.CreateConnectionResponse response,
             boolean isIncoming) {
         PhoneAccountHandle accountHandle = request.getAccountHandle();
         if (accountHandle == null) {
@@ -67,9 +61,12 @@
         if (!mRemoteConnectionServices.containsKey(componentName)) {
             throw new UnsupportedOperationException("accountHandle not supported: "
                     + componentName);
-        } else {
-            RemoteConnectionService remoteService = mRemoteConnectionServices.get(componentName);
-            remoteService.createRemoteConnection(request, response, isIncoming);
         }
+
+        RemoteConnectionService remoteService = mRemoteConnectionServices.get(componentName);
+        if (remoteService != null) {
+            return remoteService.createRemoteConnection(request, isIncoming);
+        }
+        return null;
     }
 }
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 10569ab..e6f47d2a 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -27,9 +27,9 @@
 import android.text.TextUtils;
 
 import com.android.internal.os.SomeArgs;
-import com.android.internal.telecomm.ICallVideoProvider;
 import com.android.internal.telecomm.IConnectionService;
 import com.android.internal.telecomm.IConnectionServiceAdapter;
+import com.android.internal.telecomm.IVideoCallProvider;
 import com.android.internal.telecomm.RemoteServiceCallback;
 
 import java.util.LinkedList;
@@ -69,8 +69,6 @@
     private final ComponentName mComponentName;
 
     private String mConnectionId;
-    private ConnectionRequest mPendingRequest;
-    private ConnectionService.CreateConnectionResponse<RemoteConnection> mPendingResponse;
     // Remote connection services only support a single connection.
     private RemoteConnection mConnection;
 
@@ -84,8 +82,6 @@
                         ConnectionRequest request = (ConnectionRequest) args.arg1;
                         if (isPendingConnection(request.getCallId())) {
                             ParcelableConnection parcel = (ParcelableConnection) args.arg2;
-                            mConnection = new RemoteConnection(
-                                    mConnectionService, request.getCallId());
                             mConnection.setState(parcel.getState());
                             mConnection.setCallCapabilities(parcel.getCapabilities());
                             mConnection.setHandle(
@@ -94,9 +90,6 @@
                                     parcel.getCallerDisplayName(),
                                     parcel.getCallerDisplayNamePresentation());
                             // TODO: Do we need to support video providers for remote connections?
-
-                            mPendingResponse.onSuccess(request, mConnection);
-                            clearPendingInformation();
                         }
                     } finally {
                         args.recycle();
@@ -108,9 +101,8 @@
                     try {
                         ConnectionRequest request = (ConnectionRequest) args.arg1;
                         if (isPendingConnection(request.getCallId())) {
-                            mPendingResponse.onFailure(request, args.argi1, (String) args.arg2);
-                            mConnectionId = null;
-                            clearPendingInformation();
+                            // TODO: How do we propogate the failure codes?
+                            destroyConnection();
                         }
                     } finally {
                         args.recycle();
@@ -120,9 +112,7 @@
                 case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
                     ConnectionRequest request = (ConnectionRequest) msg.obj;
                     if (isPendingConnection(request.getCallId())) {
-                        mPendingResponse.onCancel(request);
-                        mConnectionId = null;
-                        clearPendingInformation();
+                        destroyConnection();
                     }
                     break;
                 }
@@ -360,8 +350,8 @@
         }
 
         @Override
-        public void setCallVideoProvider(
-                String connectionId, ICallVideoProvider callVideoProvider) {
+        public void setVideoCallProvider(
+                String connectionId, IVideoCallProvider videoCallProvider) {
             // not supported for remote connections.
         }
 
@@ -431,11 +421,7 @@
         release();
     }
 
-    final void createRemoteConnection(
-            ConnectionRequest request,
-            ConnectionService.CreateConnectionResponse<RemoteConnection> response,
-            boolean isIncoming) {
-
+    final RemoteConnection createRemoteConnection(ConnectionRequest request, boolean isIncoming) {
         if (mConnectionId == null) {
             String id = UUID.randomUUID().toString();
             ConnectionRequest newRequest = new ConnectionRequest(
@@ -445,29 +431,20 @@
                     request.getHandlePresentation(),
                     request.getExtras(),
                     request.getVideoState());
+            mConnection = new RemoteConnection(mConnectionService, request, isIncoming);
             try {
                 mConnectionService.createConnection(newRequest, isIncoming);
                 mConnectionId = id;
-                mPendingResponse = response;
-                mPendingRequest = request;
             } catch (RemoteException e) {
-                response.onFailure(request, DisconnectCause.ERROR_UNSPECIFIED, e.toString());
+                mConnection = RemoteConnection.failure(DisconnectCause.ERROR_UNSPECIFIED,
+                        e.toString());
             }
+            return mConnection;
         } else {
-            response.onFailure(request, DisconnectCause.ERROR_UNSPECIFIED, null);
+            return RemoteConnection.failure(DisconnectCause.ERROR_UNSPECIFIED, null);
         }
     }
 
-    final List<PhoneAccountHandle> lookupAccounts(Uri handle) {
-        // TODO(santoscordon): Update this so that is actually calls into the RemoteConnection
-        // each time.
-        List<PhoneAccountHandle> accounts = new LinkedList<>();
-        accounts.add(new PhoneAccountHandle(
-                mComponentName,
-                null /* id */));
-        return accounts;
-    }
-
     /**
      * Releases the resources associated with this Remote connection service. Should be called when
      * the remote service is no longer being used.
@@ -477,7 +454,7 @@
     }
 
     private boolean isPendingConnection(String id) {
-        return TextUtils.equals(mConnectionId, id) && mPendingResponse != null;
+        return TextUtils.equals(mConnectionId, id);
     }
 
     private boolean isCurrentConnection(Object obj) {
@@ -485,11 +462,6 @@
                 TextUtils.equals(mConnectionId, (String) obj);
     }
 
-    private void clearPendingInformation() {
-        mPendingRequest = null;
-        mPendingResponse = null;
-    }
-
     private void destroyConnection() {
         mConnection.setDestroyed();
         mConnection = null;
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index ea89a53..49f95a6 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -291,6 +291,16 @@
     }
 
     /**
+     * Determine whether the device has more than one account registered and enabled.
+     *
+     * @return {@code true} if the device has more than one account registered and enabled and
+     * {@code false} otherwise.
+     */
+    public boolean hasMultipleEnabledAccounts() {
+        return getEnabledPhoneAccounts().size() > 1;
+    }
+
+    /**
      * Return the {@link PhoneAccount} for a specified {@link PhoneAccountHandle}. Object includes
      * resources which can be used in a user interface.
      *
diff --git a/telecomm/java/android/telecomm/VideoCallImpl.java b/telecomm/java/android/telecomm/VideoCallImpl.java
new file mode 100644
index 0000000..c32bcd2
--- /dev/null
+++ b/telecomm/java/android/telecomm/VideoCallImpl.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecomm;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telecomm.InCallService.VideoCall;
+import android.view.Surface;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.IVideoCallCallback;
+import com.android.internal.telecomm.IVideoCallProvider;
+
+/**
+ * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying
+ * {@link ConnectionService.VideoCallProvider}, and direct callbacks from the
+ * {@link ConnectionService.VideoCallProvider} to the appropriate {@link VideoCall.Listener}.
+ */
+public class VideoCallImpl extends VideoCall {
+    private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
+    private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
+    private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
+    private static final int MSG_CHANGE_PEER_DIMENSIONS = 4;
+    private static final int MSG_CHANGE_CALL_DATA_USAGE = 5;
+    private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6;
+
+    private final IVideoCallProvider mVideoCallProvider;
+    private final VideoCallListenerBinder mBinder;
+    private VideoCall.Listener mVideoCallListener;
+
+    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            mVideoCallProvider.asBinder().unlinkToDeath(this, 0);
+        }
+    };
+
+    /**
+     * IVideoCallCallback stub implementation.
+     */
+    private final class VideoCallListenerBinder extends IVideoCallCallback.Stub {
+        @Override
+        public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
+            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST,
+                    videoCallProfile).sendToTarget();
+        }
+
+        @Override
+        public void receiveSessionModifyResponse(int status, VideoCallProfile requestProfile,
+                VideoCallProfile responseProfile) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = status;
+            args.arg2 = requestProfile;
+            args.arg3 = responseProfile;
+            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
+        }
+
+        @Override
+        public void handleCallSessionEvent(int event) {
+            mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget();
+        }
+
+        @Override
+        public void changePeerDimensions(int width, int height) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = width;
+            args.arg2 = height;
+            mHandler.obtainMessage(MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget();
+        }
+
+        @Override
+        public void changeCallDataUsage(int dataUsage) {
+            mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, dataUsage).sendToTarget();
+        }
+
+        @Override
+        public void changeCameraCapabilities(CallCameraCapabilities cameraCapabilities) {
+            mHandler.obtainMessage(MSG_CHANGE_CAMERA_CAPABILITIES,
+                    cameraCapabilities).sendToTarget();
+        }
+    }
+
+    /** Default handler used to consolidate binder method calls onto a single thread. */
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            if (mVideoCallListener == null) {
+                return;
+            }
+
+            SomeArgs args;
+            switch (msg.what) {
+                case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
+                    mVideoCallListener.onSessionModifyRequestReceived((VideoCallProfile) msg.obj);
+                    break;
+                case MSG_RECEIVE_SESSION_MODIFY_RESPONSE:
+                    args = (SomeArgs) msg.obj;
+                    try {
+                        int status = (int) args.arg1;
+                        VideoCallProfile requestProfile = (VideoCallProfile) args.arg2;
+                        VideoCallProfile responseProfile = (VideoCallProfile) args.arg3;
+
+                        mVideoCallListener.onSessionModifyResponseReceived(
+                                status, requestProfile, responseProfile);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                case MSG_HANDLE_CALL_SESSION_EVENT:
+                    mVideoCallListener.onCallSessionEvent((int) msg.obj);
+                    break;
+                case MSG_CHANGE_PEER_DIMENSIONS:
+                    args = (SomeArgs) msg.obj;
+                    try {
+                        int width = (int) args.arg1;
+                        int height = (int) args.arg2;
+                        mVideoCallListener.onPeerDimensionsChanged(width, height);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                case MSG_CHANGE_CALL_DATA_USAGE:
+                    mVideoCallListener.onCallDataUsageChanged(msg.arg1);
+                    break;
+                case MSG_CHANGE_CAMERA_CAPABILITIES:
+                    mVideoCallListener.onCameraCapabilitiesChanged(
+                            (CallCameraCapabilities) msg.obj);
+                    break;
+                default:
+                    break;
+            }
+        }
+    };
+
+    /** {@hide} */
+    VideoCallImpl(IVideoCallProvider videoCallProvider) throws RemoteException {
+        mVideoCallProvider = videoCallProvider;
+        mVideoCallProvider.asBinder().linkToDeath(mDeathRecipient, 0);
+
+        mBinder = new VideoCallListenerBinder();
+        mVideoCallProvider.setVideoCallListener(mBinder);
+    }
+
+    /** {@inheritDoc} */
+    public void setVideoCallListener(VideoCall.Listener videoCallListener) {
+        mVideoCallListener = videoCallListener;
+    }
+
+    /** {@inheritDoc} */
+    public void setCamera(String cameraId) {
+        try {
+            mVideoCallProvider.setCamera(cameraId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void setPreviewSurface(Surface surface) {
+        try {
+            mVideoCallProvider.setPreviewSurface(surface);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void setDisplaySurface(Surface surface) {
+        try {
+            mVideoCallProvider.setDisplaySurface(surface);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void setDeviceOrientation(int rotation) {
+        try {
+            mVideoCallProvider.setDeviceOrientation(rotation);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void setZoom(float value) {
+        try {
+            mVideoCallProvider.setZoom(value);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void sendSessionModifyRequest(VideoCallProfile requestProfile) {
+        try {
+            mVideoCallProvider.sendSessionModifyRequest(requestProfile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void sendSessionModifyResponse(VideoCallProfile responseProfile) {
+        try {
+            mVideoCallProvider.sendSessionModifyResponse(responseProfile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void requestCameraCapabilities() {
+        try {
+            mVideoCallProvider.requestCameraCapabilities();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void requestCallDataUsage() {
+        try {
+            mVideoCallProvider.requestCallDataUsage();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void setPauseImage(String uri) {
+        try {
+            mVideoCallProvider.setPauseImage(uri);
+        } catch (RemoteException e) {
+        }
+    }
+}
\ No newline at end of file
diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl b/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
deleted file mode 100644
index 2689561..0000000
--- a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
+++ /dev/null
@@ -1,44 +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.internal.telecomm;
-
-import android.telecomm.CallCameraCapabilities;
-import android.telecomm.VideoCallProfile;
-
- /**
-  * Internal definition of the CallVideoClient, used for an InCall-UI to respond to video telephony
-  * related changes.
-  *
-  * @see android.telecomm.CallVideoClient
-  *
-  * {@hide}
-  */
- oneway interface ICallVideoClient {
-
-     void receiveSessionModifyRequest(in VideoCallProfile videoCallProfile);
-
-     void receiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile,
-            in VideoCallProfile responseProfile);
-
-     void handleCallSessionEvent(int event);
-
-     void updatePeerDimensions(int width, int height);
-
-     void updateCallDataUsage(int dataUsage);
-
-     void handleCameraCapabilitiesChange(in CallCameraCapabilities callCameraCapabilities);
- }
diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
index 552993f..60b5e1e 100644
--- a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
@@ -22,7 +22,7 @@
 import android.telecomm.ParcelableConnection;
 import android.telecomm.StatusHints;
 
-import com.android.internal.telecomm.ICallVideoProvider;
+import com.android.internal.telecomm.IVideoCallProvider;
 import com.android.internal.telecomm.RemoteServiceCallback;
 
 /**
@@ -65,7 +65,7 @@
 
     void queryRemoteConnectionServices(RemoteServiceCallback callback);
 
-    void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider);
+    void setVideoCallProvider(String callId, IVideoCallProvider videoCallProvider);
 
     void setVideoState(String callId, int videoState);
 
diff --git a/telecomm/java/com/android/internal/telecomm/IVideoCallCallback.aidl b/telecomm/java/com/android/internal/telecomm/IVideoCallCallback.aidl
new file mode 100644
index 0000000..a71ab0a
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/IVideoCallCallback.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.internal.telecomm;
+
+import android.telecomm.CallCameraCapabilities;
+import android.telecomm.VideoCallProfile;
+
+ /**
+  * Internal definition of the a callback interface, used for an InCallUi to respond to video
+  * telephony changes.
+  *
+  * @see android.telecomm.InCallService.VideoCall.Listener
+  *
+  * {@hide}
+  */
+oneway interface IVideoCallCallback {
+    void receiveSessionModifyRequest(in VideoCallProfile videoCallProfile);
+
+    void receiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile,
+        in VideoCallProfile responseProfile);
+
+    void handleCallSessionEvent(int event);
+
+    void changePeerDimensions(int width, int height);
+
+    void changeCallDataUsage(int dataUsage);
+
+    void changeCameraCapabilities(in CallCameraCapabilities callCameraCapabilities);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl b/telecomm/java/com/android/internal/telecomm/IVideoCallProvider.aidl
similarity index 83%
rename from telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
rename to telecomm/java/com/android/internal/telecomm/IVideoCallProvider.aidl
index 860a431..c1ba749 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IVideoCallProvider.aidl
@@ -19,15 +19,13 @@
 import android.view.Surface;
 import android.telecomm.VideoCallProfile;
 
-import com.android.internal.telecomm.ICallVideoClient;
-
 /**
- * Internal remote interface for a call video provider.
- * @see android.telecomm.CallVideoProvider
+ * Internal remote interface for a video call provider.
+ * @see android.telecomm.VideoCallProvider
  * @hide
  */
-oneway interface ICallVideoProvider {
-    void setCallVideoClient(IBinder callVideoClient);
+oneway interface IVideoCallProvider {
+    void setVideoCallListener(IBinder videoCallListenerBinder);
 
     void setCamera(String cameraId);
 
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index d2044be..aa6c47c 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -149,10 +149,21 @@
      */
     public static final int EXITED_ECM                     = 42;
 
+    /**
+     * The outgoing call failed with an unknown cause.
+     */
+    public static final int OUTGOING_FAILURE = 43;
+
+    /**
+     * The outgoing call was canceled by the {@link android.telecomm.ConnectionService}.
+     */
+    public static final int OUTGOING_CANCELED = 44;
+
     /** Smallest valid value for call disconnect codes. */
     public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
+
     /** Largest valid value for call disconnect codes. */
-    public static final int MAXIMUM_VALID_VALUE = EXITED_ECM;
+    public static final int MAXIMUM_VALID_VALUE = OUTGOING_CANCELED;
 
     /** Private constructor to avoid class instantiation. */
     private DisconnectCause() {
@@ -246,6 +257,10 @@
             return "EXITED_ECM";
         case ERROR_UNSPECIFIED:
             return "ERROR_UNSPECIFIED";
+        case OUTGOING_FAILURE:
+            return "OUTGOING_FAILURE";
+        case OUTGOING_CANCELED:
+            return "OUTGOING_CANCELED";
         default:
             return "INVALID";
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9cff765..35568cf 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -20,6 +20,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -2788,13 +2789,13 @@
 
     /**
      * Get P-CSCF address from PCO after data connection is established or modified.
-     *
+     * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
      * @return array of P-CSCF address
      * @hide
      */
-    public String[] getPcscfAddress() {
+    public String[] getPcscfAddress(String apnType) {
         try {
-            return getITelephony().getPcscfAddress();
+            return getITelephony().getPcscfAddress(apnType);
         } catch (RemoteException e) {
             return new String[0];
         }
@@ -2980,6 +2981,19 @@
 
     /** @hide */
     @SystemApi
+    public List<String> getCarrierPackageNamesForBroadcastIntent(Intent intent) {
+        try {
+            return getITelephony().getCarrierPackageNamesForBroadcastIntent(intent);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getCarrierPackageNamesForBroadcastIntent RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "getCarrierPackageNamesForBroadcastIntent NPE", ex);
+        }
+        return null;
+    }
+
+    /** @hide */
+    @SystemApi
     public void dial(String number) {
         try {
             getITelephony().dial(number);
@@ -3308,4 +3322,23 @@
         }
         return false;
     }
+
+    /**
+     * Returns the result and response from RIL for oem request
+     *
+     * @param oemReq the data is sent to ril.
+     * @param oemResp the respose data from RIL.
+     * @return negative value request was not handled or get error
+     *         0 request was handled succesfully, but no response data
+     *         positive value success, data length of response
+     * @hide
+     */
+    public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
+        try {
+            return getITelephony().invokeOemRilRequestRaw(oemReq, oemResp);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return -1;
+    }
 }
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index 5f243a0..1413e58 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -55,4 +55,15 @@
      *    Else ({@code event} is 1), meaning the specified service is added to the IMS connection.
      */
     void registrationServiceCapabilityChanged(int serviceClass, int event);
+
+    /**
+     * Notifies the application when features on a particular service enabled or
+     * disabled successfully based on user preferences.
+     *
+     * @param serviceClass a service class specified in {@link ImsServiceClass}
+     * @param enabledFeatures features enabled as defined in com.android.ims.ImsConfig#FeatureConstants.
+     * @param disabledFeatures features disabled as defined in com.android.ims.ImsConfig#FeatureConstants.
+     */
+    void registrationFeatureCapabilityChanged(int serviceClass,
+            out int[] enabledFeatures, out int[] disabledFeatures);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsService.aidl b/telephony/java/com/android/ims/internal/IImsService.aidl
index d992124..869cd9f 100644
--- a/telephony/java/com/android/ims/internal/IImsService.aidl
+++ b/telephony/java/com/android/ims/internal/IImsService.aidl
@@ -51,4 +51,15 @@
      * Config interface to get/set IMS service/capability parameters.
      */
     IImsConfig getConfigInterface();
+
+    /**
+     * Used for turning on IMS when its in OFF state.
+     */
+    void turnOnIms();
+
+    /**
+     * Used for turning off IMS when its in ON state.
+     * When IMS is OFF, device will behave as CSFB'ed.
+     */
+    void turnOffIms();
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 435c334..886de40 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.content.Intent;
 import android.os.Bundle;
 import java.util.List;
 import android.telephony.NeighboringCellInfo;
@@ -633,8 +634,9 @@
 
     /**
      * Get P-CSCF address from PCO after data connection is established or modified.
+     * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
      */
-    String[] getPcscfAddress();
+    String[] getPcscfAddress(String apnType);
 
     /**
      * Set IMS registration state
@@ -660,6 +662,17 @@
     int checkCarrierPrivilegesForPackage(String pkgname);
 
     /**
+     * Returns the package name of the carrier apps that should handle the input intent.
+     *
+     * @param packageManager PackageManager for getting receivers.
+     * @param intent Intent that will be broadcast.
+     * @return list of carrier app package names that can handle the intent.
+     *         Returns null if there is an error and an empty list if there
+     *         are no matching packages.
+     */
+    List<String> getCarrierPackageNamesForBroadcastIntent(in Intent intent);
+
+    /**
      * Set whether Android should display a simplified Mobile Network Settings UI.
      * The setting won't be persisted during power cycle.
      *
@@ -724,5 +737,16 @@
      * @return true if the operation was executed correctly.
      */
     boolean setOperatorBrandOverride(String iccId, String brand);
+
+    /**
+     * Returns the result and response from RIL for oem request
+     *
+     * @param oemReq the data is sent to ril.
+     * @param oemResp the respose data from RIL.
+     * @return negative value request was not handled or get error
+     *         0 request was handled succesfully, but no response data
+     *         positive value success, data length of response
+     */
+    int invokeOemRilRequestRaw(in byte[] oemReq, out byte[] oemResp);
 }
 
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 36c90f2..8ce7888 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -750,7 +750,7 @@
     }
 
     /** {@hide} */
-    public PackageInstaller getInstaller() {
+    public PackageInstaller getPackageInstaller() {
         throw new UnsupportedOperationException();
     }
 
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index f72e331..f4f610b 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -24,7 +24,6 @@
 import android.content.IntentFilter;
 import android.os.Handler;
 import android.os.PowerManager;
-import android.service.dreams.DozeHardware;
 import android.service.dreams.DreamService;
 import android.text.format.DateFormat;
 import android.util.Log;
@@ -49,10 +48,6 @@
     // refreshed once the dream has finished rendering a new frame.
     private static final int UPDATE_TIME_TIMEOUT = 100;
 
-    // A doze hardware message string we use for end-to-end testing.
-    // Doesn't mean anything.  Real hardware won't handle it.
-    private static final String TEST_PING_MESSAGE = "test.ping";
-
     // Not all hardware supports dozing.  We should use Display.STATE_DOZE but
     // for testing purposes it is convenient to use Display.STATE_ON so the
     // test still works on hardware that does not support dozing.
@@ -70,7 +65,6 @@
     private java.text.DateFormat mTimeFormat;
 
     private boolean mDreaming;
-    private DozeHardware mDozeHardware;
 
     private long mLastTime = Long.MIN_VALUE;
 
@@ -121,17 +115,11 @@
         super.onDreamingStarted();
 
         mDreaming = true;
-        mDozeHardware = getDozeHardware();
 
-        Log.d(TAG, "Dream started: canDoze=" + canDoze()
-                + ", dozeHardware=" + mDozeHardware);
+        Log.d(TAG, "Dream started: canDoze=" + canDoze());
 
         performTimeUpdate();
 
-        if (mDozeHardware != null) {
-            mDozeHardware.sendMessage(TEST_PING_MESSAGE, null);
-            mDozeHardware.setEnableMcu(true);
-        }
         startDozing();
     }
 
@@ -140,10 +128,6 @@
         super.onDreamingStopped();
 
         mDreaming = false;
-        if (mDozeHardware != null) {
-            mDozeHardware.setEnableMcu(false);
-            mDozeHardware = null;
-        }
 
         Log.d(TAG, "Dream ended: isDozing=" + isDozing());
 
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 397ef13..051ed0e 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -34,8 +34,10 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * This test is intended to measure the amount of memory applications use when
@@ -57,11 +59,12 @@
 
     private static final String TAG = "MemoryUsageInstrumentation";
     private static final String KEY_APPS = "apps";
-
+    private static final String KEY_PROCS = "persistent";
+    private static final String LAUNCHER_KEY = "launcher";
     private Map<String, Intent> mNameToIntent;
     private Map<String, String> mNameToProcess;
     private Map<String, String> mNameToResultKey;
-
+    private Set<String> mPersistentProcesses;
     private IActivityManager mAm;
 
     public void testMemory() {
@@ -75,35 +78,61 @@
 
         Bundle results = new Bundle();
         for (String app : mNameToResultKey.keySet()) {
-            String processName;
-            try {
-                processName = startApp(app);
-                measureMemory(app, processName, results);
-                closeApp();
-            } catch (NameNotFoundException e) {
-                Log.i(TAG, "Application " + app + " not found");
+            if (!mPersistentProcesses.contains(app)) {
+                String processName;
+                try {
+                    processName = startApp(app);
+                    measureMemory(app, processName, results);
+                    closeApp();
+                } catch (NameNotFoundException e) {
+                    Log.i(TAG, "Application " + app + " not found");
+                }
+            } else {
+                measureMemory(app, app, results);
             }
-
         }
         instrumentation.sendStatus(0, results);
     }
 
-    private void parseArgs(Bundle args) {
-        mNameToResultKey = new HashMap<String, String>();
-        String appList = args.getString(KEY_APPS);
+    private String getLauncherPackageName() {
+      Intent intent = new Intent(Intent.ACTION_MAIN);
+      intent.addCategory(Intent.CATEGORY_HOME);
+      ResolveInfo resolveInfo = getInstrumentation().getContext().
+          getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+      return resolveInfo.activityInfo.packageName;
+    }
 
-        if (appList == null)
-            return;
-
-        String appNames[] = appList.split("\\|");
-        for (String pair : appNames) {
+    private Map<String, String> parseListToMap(String list) {
+        Map<String, String> map = new HashMap<String, String>();
+        String names[] = list.split("\\|");
+        for (String pair : names) {
             String[] parts = pair.split("\\^");
             if (parts.length != 2) {
                 Log.e(TAG, "The apps key is incorectly formatted");
                 fail();
             }
+            map.put(parts[0], parts[1]);
+        }
+        return map;
+    }
 
-            mNameToResultKey.put(parts[0], parts[1]);
+    private void parseArgs(Bundle args) {
+        mNameToResultKey = new HashMap<String, String>();
+        mPersistentProcesses = new HashSet<String>();
+        String appList = args.getString(KEY_APPS);
+        String procList = args.getString(KEY_PROCS);
+        String mLauncherPackageName = getLauncherPackageName();
+        mPersistentProcesses.add(mLauncherPackageName);
+        mNameToResultKey.put(mLauncherPackageName, LAUNCHER_KEY);
+        if (appList == null && procList == null)
+            return;
+        if (appList != null) {
+            mNameToResultKey.putAll(parseListToMap(appList));
+        }
+        if (procList != null) {
+            Map<String, String> procMap = parseListToMap(procList);
+            mPersistentProcesses.addAll(procMap.keySet());
+            mNameToResultKey.putAll(procMap);
         }
     }
 
diff --git a/tests/MusicServiceDemo/AndroidManifest.xml b/tests/MusicServiceDemo/AndroidManifest.xml
index 4178a80..e00e2e2 100644
--- a/tests/MusicServiceDemo/AndroidManifest.xml
+++ b/tests/MusicServiceDemo/AndroidManifest.xml
@@ -47,7 +47,7 @@
             android:exported="true"
             >
             <intent-filter>
-                <action android:name="android.media.browse.MediaBrowseService" />
+                <action android:name="android.media.browse.MediaBrowserService" />
             </intent-filter>
         </service>
     </application>
diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java
index e5216b5..937f1e6 100644
--- a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java
+++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java
@@ -116,28 +116,34 @@
     }
 
     @Override
-    protected BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
+    public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
         return new BrowserRoot(BROWSE_URI, null);
     }
 
     @Override
-    protected List<MediaBrowserItem> onLoadChildren(Uri parentUri) {
-        final ArrayList<MediaBrowserItem> results = new ArrayList();
+    public void onLoadChildren(final Uri parentUri,
+            final Result<List<MediaBrowserItem>> result) {
+        new Handler().postDelayed(new Runnable() {
+                public void run() {
+                    final ArrayList<MediaBrowserItem> list = new ArrayList();
 
-        for (int i=0; i<10; i++) {
-            results.add(new MediaBrowserItem.Builder(
-                    Uri.withAppendedPath(BASE_URI, Integer.toString(i)),
-                    MediaBrowserItem.FLAG_BROWSABLE, "Title " + i)
-                    .setSummary("Summary " + i)
-                    .build());
-        }
+                    for (int i=0; i<10; i++) {
+                        list.add(new MediaBrowserItem.Builder(
+                                    Uri.withAppendedPath(BASE_URI, Integer.toString(i)),
+                                    MediaBrowserItem.FLAG_BROWSABLE, "Title " + i)
+                                .setSummary("Summary " + i)
+                                .build());
+                    }
 
-        return results;
+                    result.sendResult(list);
+                }
+            }, 2000);
+        result.detach();
     }
 
     @Override
-    protected Bitmap onGetThumbnail(Uri uri, int width, int height) {
-        return null;
+    public void onLoadIcon(Uri uri, int width, int height, Result<Bitmap> result) {
+        result.sendResult(null);
     }
 
     /*
diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
new file mode 100644
index 0000000..407a9d7
--- /dev/null
+++ b/tests/SoundTriggerTests/Android.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := SoundTriggerTests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SoundTriggerTests/AndroidManifest.xml b/tests/SoundTriggerTests/AndroidManifest.xml
new file mode 100644
index 0000000..5e5a108
--- /dev/null
+++ b/tests/SoundTriggerTests/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.hardware.soundtrigger">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.hardware.soundtrigger"
+                     android:label="Tests for android.hardware.soundtrigger" />
+</manifest>
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
new file mode 100644
index 0000000..5d32c66e
--- /dev/null
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger;
+
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.os.Parcel;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.UUID;
+
+public class SoundTriggerTest extends InstrumentationTestCase {
+    private Random mRandom = new Random();
+
+    @SmallTest
+    public void testKeyphraseParcelUnparcel_noUsers() throws Exception {
+        Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", null);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        keyphrase.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(keyphrase.id, unparceled.id);
+        assertNull(unparceled.users);
+        assertEquals(keyphrase.locale, unparceled.locale);
+        assertEquals(keyphrase.text, unparceled.text);
+    }
+
+    @SmallTest
+    public void testKeyphraseParcelUnparcel_zeroUsers() throws Exception {
+        Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[0]);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        keyphrase.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(keyphrase.id, unparceled.id);
+        assertTrue(Arrays.equals(keyphrase.users, unparceled.users));
+        assertEquals(keyphrase.locale, unparceled.locale);
+        assertEquals(keyphrase.text, unparceled.text);
+    }
+
+    @SmallTest
+    public void testKeyphraseParcelUnparcel_pos() throws Exception {
+        Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[] {1, 2, 3, 4, 5});
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        keyphrase.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(keyphrase.id, unparceled.id);
+        assertTrue(Arrays.equals(keyphrase.users, unparceled.users));
+        assertEquals(keyphrase.locale, unparceled.locale);
+        assertEquals(keyphrase.text, unparceled.text);
+    }
+
+    @SmallTest
+    public void testKeyphraseSoundModelParcelUnparcel_noData() throws Exception {
+        Keyphrase[] keyphrases = new Keyphrase[2];
+        keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0});
+        keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2});
+        KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), null, keyphrases);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        ksm.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(ksm.uuid, unparceled.uuid);
+        assertNull(unparceled.data);
+        assertEquals(ksm.type, unparceled.type);
+        assertTrue(Arrays.equals(keyphrases, unparceled.keyphrases));
+    }
+
+    @SmallTest
+    public void testKeyphraseSoundModelParcelUnparcel_zeroData() throws Exception {
+        Keyphrase[] keyphrases = new Keyphrase[2];
+        keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0});
+        keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2});
+        KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), new byte[0],
+                keyphrases);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        ksm.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(ksm.uuid, unparceled.uuid);
+        assertEquals(ksm.type, unparceled.type);
+        assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases));
+        assertTrue(Arrays.equals(ksm.data, unparceled.data));
+    }
+
+    @SmallTest
+    public void testKeyphraseSoundModelParcelUnparcel_noKeyphrases() throws Exception {
+        byte[] data = new byte[10];
+        mRandom.nextBytes(data);
+        KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, null);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        ksm.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(ksm.uuid, unparceled.uuid);
+        assertEquals(ksm.type, unparceled.type);
+        assertNull(unparceled.keyphrases);
+        assertTrue(Arrays.equals(ksm.data, unparceled.data));
+    }
+
+    @SmallTest
+    public void testKeyphraseSoundModelParcelUnparcel_zeroKeyphrases() throws Exception {
+        byte[] data = new byte[10];
+        mRandom.nextBytes(data);
+        KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data,
+                new Keyphrase[0]);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        ksm.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(ksm.uuid, unparceled.uuid);
+        assertEquals(ksm.type, unparceled.type);
+        assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases));
+        assertTrue(Arrays.equals(ksm.data, unparceled.data));
+    }
+
+    @LargeTest
+    public void testKeyphraseSoundModelParcelUnparcel_largeData() throws Exception {
+        Keyphrase[] keyphrases = new Keyphrase[2];
+        keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0});
+        keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2});
+        byte[] data = new byte[200 * 1024];
+        mRandom.nextBytes(data);
+        KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, keyphrases);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        ksm.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(ksm.uuid, unparceled.uuid);
+        assertEquals(ksm.type, unparceled.type);
+        assertTrue(Arrays.equals(ksm.data, unparceled.data));
+        assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases));
+    }
+
+    @SmallTest
+    public void testRecognitionEventParcelUnparcel_noData() throws Exception {
+        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1,
+                true, 2, 3, 4, null);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        re.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(re, unparceled);
+    }
+
+    @SmallTest
+    public void testRecognitionEventParcelUnparcel_zeroData() throws Exception {
+        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE, 1,
+                true, 2, 3, 4, new byte[1]);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        re.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(re, unparceled);
+    }
+
+    @SmallTest
+    public void testRecognitionEventParcelUnparcel_largeData() throws Exception {
+        byte[] data = new byte[200 * 1024];
+        mRandom.nextBytes(data);
+        RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1,
+                false, 2, 3, 4, data);
+
+        // Write to a parcel
+        Parcel parcel = Parcel.obtain();
+        re.writeToParcel(parcel, 0);
+
+        // Read from it
+        parcel.setDataPosition(0);
+        RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel);
+
+        // Verify that they are the same
+        assertEquals(re, unparceled);
+    }
+}
diff --git a/tests/UsesFeature2Test/Android.mk b/tests/UsesFeature2Test/Android.mk
new file mode 100644
index 0000000..cc784d7
--- /dev/null
+++ b/tests/UsesFeature2Test/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := UsesFeature2Test
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/UsesFeature2Test/AndroidManifest.xml b/tests/UsesFeature2Test/AndroidManifest.xml
new file mode 100644
index 0000000..724d186
--- /dev/null
+++ b/tests/UsesFeature2Test/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.test.usesfeature2">
+
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" />
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+
+    <uses-feature android:name="android.hardware.sensor.accelerometer" />
+    <feature-group android:label="@string/minimal">
+        <uses-feature android:name="android.hardware.dpad" />
+        <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" />
+    </feature-group>
+    <feature-group android:label="@string/gamepad">
+        <uses-feature android:name="android.hardware.gamepad" />
+    </feature-group>
+
+    <application android:label="@string/app_title">
+        <activity android:name="ActivityMain">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid.xml b/tests/UsesFeature2Test/res/values/values.xml
similarity index 70%
copy from packages/DocumentsUI/res/drawable/item_doc_grid.xml
copy to tests/UsesFeature2Test/res/values/values.xml
index 3f036f7..2ee9107 100644
--- a/packages/DocumentsUI/res/drawable/item_doc_grid.xml
+++ b/tests/UsesFeature2Test/res/values/values.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_grid_card_background" />
-</selector>
+<resources>
+    <string name="app_title">Uses Feature 2.0</string>
+    <string name="minimal">Crippled experience</string>
+    <string name="gamepad">Gamer experience</string>
+</resources>
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index a16b749..ee62e5e 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -100,7 +100,7 @@
         </activity>
         <activity
             android:name="VectorDrawableStaticPerf"
-            android:label="Performance of vector images" >
+            android:label="System icons" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 66a9452..705cc34 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -13,22 +13,18 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="48dp"
-        android:width="48dp" />
-
-    <viewport
+        android:width="48dp"
         android:viewportHeight="480"
-        android:viewportWidth="480" />
+        android:viewportWidth="480" >
 
     <group>
         <path
             android:name="box1"
-            android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
-            android:fill="?android:attr/colorControlActivated"
-            android:stroke="?android:attr/colorControlActivated"
+            android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
+            android:fillColor="?android:attr/colorControlActivated"
+            android:strokeColor="?android:attr/colorControlActivated"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
     </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
index 40f23f0..f5d647c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
@@ -12,14 +12,10 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport android:viewportWidth="320"
-          android:viewportHeight="320"/>
+        android:height="64dp" android:viewportWidth="320"
+          android:viewportHeight="320">
     <group
         android:rotation="180"
         android:pivotX="70"
@@ -27,8 +23,8 @@
         <path
             android:name="house"
             android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
-            android:fill="#ff440000"
-            android:stroke="#FF00FF00"
+            android:fillColor="#ff440000"
+            android:strokeColor="#FF00FF00"
             android:strokeWidth="10"
             android:trimPathStart=".1"
             android:trimPathEnd=".9"/>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
index 2fdb676..a0b0e00 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
@@ -14,65 +14,58 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true" >
-
-    <size
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="12.25"
-        android:viewportWidth="7.30625" />
+        android:viewportWidth="7.30625" >
 
     <group
         android:pivotX="3.65"
         android:pivotY="6.125"
         android:rotation="-30" >
-        <path
+        <clip-path
             android:name="clip1"
-            android:clipToPath="true"
             android:pathData="
                 M 0, 6.125
                 l 7.3, 0
                 l 0, 12.25
-                l -7.3, 0
+                l-7.3, 0
                 z" />
     </group>
     <group>
         <path
             android:name="one"
-            android:fill="#ff88ff"
-            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-                l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l -5.046875,0.0 0.0,-1.0Z" />
+            android:fillColor="#ff88ff"
+            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+                l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+                l-5.046875,0.0 0.0-1.0Z" />
     </group>
     <group
         android:pivotX="3.65"
         android:pivotY="6.125"
         android:rotation="-30" >
-        <path
+        <clip-path
             android:name="clip2"
-            android:clipToPath="true"
             android:pathData="
                 M 0, 0
                 l 7.3, 0
                 l 0, 6.125
-                l -7.3, 0
+                l-7.3, 0
                 z" />
     </group>
     <group>
         <path
             android:name="two"
-            android:fill="#ff88ff"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
+            android:fillColor="#ff88ff"
+            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+                        q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
+                        q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
+                        q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
+                        q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875
+                        q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
+                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
+                        q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
+                        q-0.78125024,0.8125-2.2187502,2.265625Z" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
index 296e026..5a7f380 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
@@ -13,57 +13,44 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-
-    <size
             android:width="64dp"
-            android:height="64dp"/>
-
-    <viewport
+            android:height="64dp"
             android:viewportWidth="7.30625"
-            android:viewportHeight="12.25"/>
+            android:viewportHeight="12.25">
 
     <group>
-        <path
+        <clip-path
                 android:name="clip1"
                 android:pathData="
                 M 3.65, 6.125
-                m -.001, 0
+                m-.001, 0
                 a .001,.001 0 1,0 .002,0
-                a .001,.001 0 1,0 -.002,0z"
-                android:clipToPath="true"
-                android:fill="#112233"
-                />
-
+                a .001,.001 0 1,0-.002,0z"/>
         <path
                 android:name="one"
-                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-                l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l -5.046875,0.0 0.0,-1.0Z"
-                android:fill="#ff88ff"
-                />
-        <path
+                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+                l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+                l-5.046875,0.0 0.0-1.0Z"
+                android:fillColor="#ff88ff"/>
+
+        <clip-path
                 android:name="clip2"
                 android:pathData="
                 M 3.65, 6.125
-                m -6, 0
+                m-6, 0
                 a 6,6 0 1,0 12,0
-                a 6,6 0 1,0 -12,0z"
-                android:clipToPath="true"
-                android:fill="#112233"
-                />
+                a 6,6 0 1,0-12,0z"/>
         <path
                 android:name="two"
-                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
-                android:fill="#ff88ff"
-                />
+                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+                        q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
+                        q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
+                        q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
+                        q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875
+                        q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
+                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
+                        q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
+                        q-0.78125024,0.8125-2.2187502,2.265625Z"
+                android:fillColor="#ff88ff"/>
     </group>
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index 1633326..5b1f6ab 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -14,35 +14,30 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-
-    <size
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="12.25"
-        android:viewportWidth="7.30625" />
+        android:viewportWidth="7.30625" >
 
     <group>
         <path
             android:name="one"
-            android:fill="#ffff00"
-            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-                l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l -5.046875,0.0 0.0,-1.0Z" />
+            android:fillColor="#ffff00"
+            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+                l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+                l-5.046875,0.0 0.0-1.0Z" />
         <path
             android:name="two"
-            android:fill="#ffff00"
+            android:fillColor="#ffff00"
             android:fillOpacity="0"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
+            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+                        q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
+                        q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
+                        q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
+                        q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875
+                        q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
+                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
+                        q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
+                        q-0.78125024,0.8125-2.2187502,2.265625Z" />
     </group>
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
index ab5f7f4..98b6235 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
@@ -12,41 +12,37 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
             android:width="64dp"
-            android:height="64dp"/>
-
-    <viewport
+            android:height="64dp"
             android:viewportWidth="700"
-            android:viewportHeight="700"/>
+            android:viewportHeight="700">
 
     <group>
         <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
               android:name="path2451"
-              android:fill="#00000000"
-              android:stroke="#FF000000"
+              android:fillColor="#00000000"
+              android:strokeColor="#FF000000"
               android:strokeWidth="30.65500000000000"/>
         <path android:pathData="M 365.015 311.066"
               android:name="path2453"
-              android:fill="#00000000"
-              android:stroke="#FF000000"
+              android:fillColor="#00000000"
+              android:strokeColor="#FF000000"
               android:strokeWidth="30.655000000000001"/>
         <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
               android:name="path2455"
-              android:stroke="#FF000000"
-              android:fill="#FFFFFFFF"
+              android:strokeColor="#FF000000"
+              android:fillColor="#FFFFFFFF"
               android:strokeWidth="30.655000000000001"/>
         <path android:pathData="M 170.515 451.566L 305.61 313.46"
               android:name="path2457"
-              android:fill="#00000000"
-              android:stroke="#000000"
+              android:fillColor="#00000000"
+              android:strokeColor="#000000"
               android:strokeWidth="30.655000000000001"/>
         <path android:pathData="M 557.968 449.974L 426.515 315.375"
               android:name="path2459"
-              android:fill="#00000000"
-              android:stroke="#000000"
+              android:fillColor="#00000000"
+              android:strokeColor="#000000"
               android:strokeWidth="30.655000000000001"/>
     </group>
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
index 7c7e679..88c4a1e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
@@ -12,21 +12,18 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"   >
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
             android:width="64dp"
-            android:height="64dp"/>
-
-    <viewport android:viewportWidth="140"
-          android:viewportHeight="110"/>
+            android:height="64dp" android:viewportWidth="140"
+          android:viewportHeight="110">
 
     <group>
         <path
                 android:name="back"
-                android:pathData="M 20,55 l 35.3,-35.3 7.07,7.07 -35.3,35.3 z
-              M 27,50 l 97,0 0,10 -97,0 z
-              M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z"
-                android:fill="#ffffffff"
+                android:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
+              M 27,50 l 97,0 0,10-97,0 z
+              M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z"
+                android:fillColor="#ffffffff"
                 />
     </group>
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
index 59f7459..75529e2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
@@ -12,22 +12,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
             android:width="64dp"
-            android:height="64dp"/>
-
-
-    <viewport android:viewportWidth="600"
-          android:viewportHeight="600"/>
+            android:height="64dp" android:viewportWidth="600"
+          android:viewportHeight="600">
 
     <group>
         <path
                 android:name="pie1"
                 android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
-                android:fill="#ffffcc00"
-                android:stroke="#FF00FF00"
+                android:fillColor="#ffffcc00"
+                android:strokeColor="#FF00FF00"
                 android:strokeWidth="1"/>
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index c93c85f..853a770 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="200"
-        android:viewportWidth="200" />
+        android:viewportWidth="200" >
 
     <group
         android:pivotX="100"
@@ -29,8 +25,8 @@
         android:rotation="90">
         <path
             android:name="house"
-            android:fill="#ffffffff"
-            android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"/>
+            android:fillColor="#ffffffff"
+            android:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
index 8484e9e..83ed194 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -14,33 +14,29 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportWidth="200"
-        android:viewportHeight="200"/>
+        android:viewportHeight="200">
 
     <group>
         <path
             android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
         <path
             android:name="bar2"
-            android:fill="#FFFFFFFF"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
         <path
             android:name="bar1"
-            android:fill="#FF555555"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
+            android:fillColor="#FF555555"
+            android:pathData="M14.001,34.645   L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
         <path
             android:name="bar0"
-            android:fill="#FF555555"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
+            android:fillColor="#FF555555"
+            android:pathData="M0,20.502l6.999,7.071   c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index 3422bbf..b3d7d8e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -13,26 +13,22 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="80"
-        android:viewportWidth="40" />
+        android:viewportWidth="40" >
 
     <group>
         <path
             android:name="battery"
-            android:fill="#3388ff"
+            android:fillColor="#3388ff"
             android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
-            android:stroke="#ff8833"
+            android:strokeColor="#ff8833"
             android:strokeWidth="1" />
         <path
             android:name="spark"
-            android:fill="#FFFF0000"
+            android:fillColor="#FFFF0000"
             android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index a212def..2c8b751 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="600"
-        android:viewportWidth="600" />
+        android:viewportWidth="600" >
 
     <group
         android:name="rotationGroup"
@@ -30,16 +26,16 @@
         android:rotation="45.0" >
         <path
             android:name="pie1"
-            android:fill="#00000000"
+            android:fillColor="#00000000"
             android:pathData="M300,70 a230,230 0 1,0 1,0 z"
-            android:stroke="#FF777777"
+            android:strokeColor="#FF777777"
             android:strokeWidth="70"
             android:trimPathEnd=".75"
             android:trimPathOffset="0"
             android:trimPathStart="0" />
         <path
             android:name="v"
-            android:fill="#000000"
+            android:fillColor="#000000"
             android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
 
         <group
@@ -55,7 +51,7 @@
                 <path
                     android:name="twoLines1"
                     android:pathData="@string/twoLinePathData"
-                    android:stroke="#FFFF0000"
+                    android:strokeColor="#FFFF0000"
                     android:strokeWidth="20" />
 
                 <group
@@ -69,9 +65,9 @@
                         android:rotation="-45.0" >
                         <path
                             android:name="twoLines2"
-                            android:fill="#FF00FF00"
+                            android:fillColor="#FF00FF00"
                             android:pathData="@string/twoLinePathData"
-                            android:stroke="#FF00FF00"
+                            android:strokeColor="#FF00FF00"
                             android:strokeWidth="20" />
 
                         <group
@@ -86,7 +82,7 @@
                                 <path
                                     android:name="twoLines3"
                                     android:pathData="@string/twoLinePathData"
-                                    android:stroke="#FF0000FF"
+                                    android:strokeColor="#FF0000FF"
                                     android:strokeWidth="20" />
                             </group>
                         </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index 8c946df..2468a1b 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -13,28 +13,24 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="400"
-        android:viewportWidth="600" />
+        android:viewportWidth="600" >
 
     <group>
         <path
             android:name="pie1"
-            android:fill="#ffffffff"
+            android:fillColor="#ffffffff"
             android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
-            android:stroke="#FF00FF00"
+            android:strokeColor="#FF00FF00"
             android:strokeWidth="1" />
         <path
             android:name="half"
-            android:fill="#FFFF0000"
+            android:fillColor="#FFFF0000"
             android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
-            android:stroke="#FF0000FF"
+            android:strokeColor="#FF0000FF"
             android:strokeWidth="5" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index 8d4ca61..01e24d302 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="500"
-        android:viewportWidth="800" />
+        android:viewportWidth="800" >
 
     <group
         android:pivotX="90"
@@ -34,8 +30,8 @@
            a25,25 -30 0,1 100,-50 l 50,-25
            a25,37 -30 0,1 100,-50 l 50,-25
            a25,50 -30 0,1 100,-50 l 50,-25"
-            android:fill="#00000000"
-            android:stroke="#FF00FF00"
+            android:fillColor="#00000000"
+            android:strokeColor="#FF00FF00"
             android:strokeWidth="10" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index b08e157..4bab2e3 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="400"
-        android:viewportWidth="500" />
+        android:viewportWidth="500" >
 
     <group
         android:pivotX="250"
@@ -29,9 +25,9 @@
         android:rotation="180">
         <path
             android:name="house"
-            android:fill="#ff440000"
+            android:fillColor="#ff440000"
             android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:stroke="#FFFF0000"
+            android:strokeColor="#FFFF0000"
             android:strokeWidth="10" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index ae85d9b..107cda2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -13,25 +13,21 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="200"
-        android:viewportWidth="200" />
+        android:viewportWidth="200" >
 
     <group>
         <path
             android:name="background1"
             android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
-            android:fill="#FF000000"/>
+            android:fillColor="#FF000000"/>
         <path
             android:name="background2"
             android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
-            android:fill="#FF000000"/>
+            android:fillColor="#FF000000"/>
     </group>
     <group
         android:pivotX="100"
@@ -44,7 +40,7 @@
         <path
             android:name="twoLines"
             android:pathData="M 100,10 v 90 M 10,100 h 90"
-            android:stroke="#FF00FF00"
+            android:strokeColor="#FF00FF00"
             android:strokeWidth="10" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
index c28aff4..8019549 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
@@ -12,21 +12,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
             android:width="64dp"
-            android:height="64dp"/>
-
-    <viewport android:viewportWidth="1200"
-          android:viewportHeight="600"/>
+            android:height="64dp" android:viewportWidth="1200"
+          android:viewportHeight="600">
 
     <group>
         <path
                 android:name="house"
                 android:pathData="M200,300 Q400,50 600,300 T1000,300"
-                android:fill="#00000000"
-                android:stroke="#FFFF0000"
+                android:fillColor="#00000000"
+                android:strokeColor="#FFFF0000"
                 android:strokeWidth="10"/>
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index d7042fd..c93bdb9 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -13,22 +13,18 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="400"
-        android:viewportWidth="500" />
+        android:viewportWidth="500" >
 
     <group>
         <path
             android:name="house"
             android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:fill="#00000000"
-            android:stroke="#FFFFFF00"
+            android:fillColor="#00000000"
+            android:strokeColor="#FFFFFF00"
             android:strokeWidth="10" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index 47a9574..996b6be 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="800"
-        android:viewportWidth="1000" />
+        android:viewportWidth="1000" >
 
     <group>
         <path
@@ -29,8 +25,8 @@
             android:pathData="M10,300 Q400,550 600,300 T1000,300"
             android:pivotX="90"
             android:pivotY="100"
-            android:fill="#00000000"
-            android:stroke="#FFFF0000"
+            android:fillColor="#00000000"
+            android:strokeColor="#FFFF0000"
             android:strokeWidth="60" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
index b8af7e2..5802144 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
@@ -13,25 +13,21 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="480"
-        android:viewportWidth="480" />
+        android:viewportWidth="480" >
 
     <group>
         <path
             android:name="edit"
-            android:fill="#FF00FFFF"
+            android:fillColor="#FF00FFFF"
             android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
     c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
     c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
     c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
-            android:stroke="#FF000000"
+            android:strokeColor="#FF000000"
             android:strokeWidth="10" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml
index e0013e7..5626b44 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml
@@ -13,25 +13,21 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="200"
-        android:viewportWidth="200" />
+        android:viewportWidth="200" >
 
     <group>
         <path
             android:name="background1"
             android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
-            android:fill="#FF000000"/>
+            android:fillColor="#FF000000"/>
         <path
             android:name="background2"
             android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
-            android:fill="#FF000000"/>
+            android:fillColor="#FF000000"/>
     </group>
     <group
         android:pivotX="0"
@@ -44,7 +40,7 @@
         <path
             android:name="twoLines"
             android:pathData="M 100,10 v 90 M 10,100 h 90"
-            android:stroke="#FF00FF00"
+            android:strokeColor="#FF00FF00"
             android:strokeWidth="10" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml
index 8d38cb5..5b40d0d0 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml
@@ -13,24 +13,20 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="400"
-        android:viewportWidth="400" />
+        android:viewportWidth="400" >
 
     <group android:name="backgroundGroup" >
         <path
             android:name="background1"
-            android:fill="#80000000"
+            android:fillColor="#80000000"
             android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
         <path
             android:name="background2"
-            android:fill="#80000000"
+            android:fillColor="#80000000"
             android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
     </group>
     <group
@@ -40,7 +36,7 @@
         <path
             android:name="twoLines"
             android:pathData="M 0,0 v 100 M 0,0 h 100"
-            android:stroke="#FFFF0000"
+            android:strokeColor="#FFFF0000"
             android:strokeWidth="20" />
 
         <group
@@ -51,7 +47,7 @@
             <path
                 android:name="twoLines1"
                 android:pathData="M 0,0 v 100 M 0,0 h 100"
-                android:stroke="#FF00FF00"
+                android:strokeColor="#FF00FF00"
                 android:strokeWidth="20" />
 
             <group
@@ -62,7 +58,7 @@
                     <path
                         android:name="twoLines2"
                         android:pathData="M 0,0 v 100 M 0,0 h 100"
-                        android:stroke="#FF0000FF"
+                        android:strokeColor="#FF0000FF"
                         android:strokeWidth="20" />
                 </group>
             </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml
index 52acd7a..6ab6ffd 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml
@@ -13,24 +13,20 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="400"
-        android:viewportWidth="400" />
+        android:viewportWidth="400" >
 
     <group android:name="backgroundGroup" >
         <path
             android:name="background1"
-            android:fill="#80000000"
+            android:fillColor="#80000000"
             android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
         <path
             android:name="background2"
-            android:fill="#80000000"
+            android:fillColor="#80000000"
             android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
     </group>
     <group
@@ -40,7 +36,7 @@
         <path
             android:name="twoLines"
             android:pathData="@string/twoLinePathData"
-            android:stroke="#FFFF0000"
+            android:strokeColor="#FFFF0000"
             android:strokeWidth="20" />
 
         <group
@@ -51,7 +47,7 @@
             <path
                 android:name="twoLines1"
                 android:pathData="@string/twoLinePathData"
-                android:stroke="#FF00FF00"
+                android:strokeColor="#FF00FF00"
                 android:strokeWidth="20" />
 
             <group
@@ -62,7 +58,7 @@
                     <path
                         android:name="twoLines3"
                         android:pathData="@string/twoLinePathData"
-                        android:stroke="#FF0000FF"
+                        android:strokeColor="#FF0000FF"
                         android:strokeWidth="20" />
                 </group>
             </group>
@@ -75,8 +71,8 @@
                     <path
                         android:name="twoLines2"
                         android:pathData="@string/twoLinePathData"
-                        android:fill="?android:attr/colorForeground"
-                        android:stroke="?android:attr/colorForeground"
+                        android:fillColor="?android:attr/colorForeground"
+                        android:strokeColor="?android:attr/colorForeground"
                         android:strokeWidth="20" />
                 </group>
             </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml
index c062d70..5c1ccaa 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml
@@ -13,25 +13,21 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="400"
-        android:viewportWidth="400" />
+        android:viewportWidth="400" >
 
     <group android:name="backgroundGroup"
         android:alpha = "0.5" >
         <path
             android:name="background1"
-            android:fill="#FF000000"
+            android:fillColor="#FF000000"
             android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
         <path
             android:name="background2"
-            android:fill="#FF000000"
+            android:fillColor="#FF000000"
             android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
     </group>
     <group
@@ -42,7 +38,7 @@
         <path
             android:name="twoLines"
             android:pathData="@string/twoLinePathData"
-            android:stroke="#FFFF0000"
+            android:strokeColor="#FFFF0000"
             android:strokeWidth="20" />
 
         <group
@@ -54,7 +50,7 @@
             <path
                 android:name="twoLines1"
                 android:pathData="@string/twoLinePathData"
-                android:stroke="#FF00FF00"
+                android:strokeColor="#FF00FF00"
                 android:strokeWidth="20" />
 
             <group
@@ -66,7 +62,7 @@
                     <path
                         android:name="twoLines3"
                         android:pathData="@string/twoLinePathData"
-                        android:stroke="#FF0000FF"
+                        android:strokeColor="#FF0000FF"
                         android:strokeWidth="20" />
                 </group>
             </group>
@@ -80,8 +76,8 @@
                     <path
                         android:name="twoLines2"
                         android:pathData="@string/twoLinePathData"
-                        android:fill="?android:attr/colorForeground"
-                        android:stroke="?android:attr/colorForeground"
+                        android:fillColor="?android:attr/colorForeground"
+                        android:strokeColor="?android:attr/colorForeground"
                         android:strokeWidth="20" />
                 </group>
             </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml
index a3f0447..069a531 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="400"
-        android:viewportWidth="400" />
+        android:viewportWidth="400" >
 
     <group
         android:name="FirstLevelGroup"
@@ -34,7 +30,7 @@
             android:translateX="-100.0"
             android:translateY="50.0" >
             <path
-                android:fill="#FF00FF00"
+                android:fillColor="#FF00FF00"
                 android:pathData="@string/rectangle200" />
 
             <group
@@ -43,7 +39,7 @@
                 android:translateX="-100.0"
                 android:translateY="50.0" >
                 <path
-                    android:fill="#FF0000FF"
+                    android:fillColor="#FF0000FF"
                     android:pathData="@string/rectangle200" />
             </group>
             <group
@@ -52,7 +48,7 @@
                 android:translateX="100.0"
                 android:translateY="50.0" >
                 <path
-                    android:fill="#FF000000"
+                    android:fillColor="#FF000000"
                     android:pathData="@string/rectangle200" />
             </group>
         </group>
@@ -62,7 +58,7 @@
             android:translateX="100.0"
             android:translateY="50.0" >
             <path
-                android:fill="#FF0000FF"
+                android:fillColor="#FF0000FF"
                 android:pathData="@string/rectangle200" />
 
             <group
@@ -71,7 +67,7 @@
                 android:translateX="-100.0"
                 android:translateY="50.0" >
                 <path
-                    android:fill="#FFFF0000"
+                    android:fillColor="#FFFF0000"
                     android:pathData="@string/rectangle200" />
             </group>
             <group
@@ -80,13 +76,13 @@
                 android:translateX="100.0"
                 android:translateY="50.0" >
                 <path
-                    android:fill="#FF00FF00"
+                    android:fillColor="#FF00FF00"
                     android:pathData="@string/rectangle200" />
             </group>
         </group>
 
         <path
-            android:fill="#FFFF0000"
+            android:fillColor="#FFFF0000"
             android:pathData="@string/rectangle200" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
index c8840f5..7be49a9 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="128dp"
-        android:width="128dp" />
-
-    <viewport
+        android:width="128dp"
         android:viewportHeight="480"
-        android:viewportWidth="480" />
+        android:viewportWidth="480" >
 
     <group
         android:name="root"
@@ -29,14 +25,14 @@
         android:translateY="240.0" >
         <path
             android:name="favorite"
-            android:fill="#ff000000"
+            android:fillColor="#ff000000"
             android:pathData="M2.100006104,-6
                 C0.1449127197,-6,1.600006104,-5.975006104,0,-5.975006104
-                C-1.574996948,-5.975006104,0.00309753418,-6,-1.949996948,-6
+                C-1.574996948,-5.975006104,0.00309753418,-6-1.949996948-6
                 C-4.492996216,-6,-5.949996948,-3.718399048,-5.949996948,-1.149993896
                 C-5.949996948,2.379302979,-5.699996948,5.100006104,0,5.100006104
                 C5.699996948,5.100006104,6,2.379302979,6,-1.149993896
-                C6,-3.718399048,4.643005371,-6,2.100006104,-6" />
+                C6,-3.718399048,4.643005371-6,2.100006104-6" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml
index 558de94..7839ad1 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="256"
-        android:viewportWidth="256" />
+        android:viewportWidth="256" >
 
     <group
         android:name="shape_layer_1"
@@ -30,7 +26,7 @@
         <group android:name="sun" >
             <path
                 android:name="ellipse_path_1"
-                android:fill="#ffff8000"
+                android:fillColor="#ffff8000"
                 android:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
 
             <group
@@ -38,7 +34,7 @@
                 android:translateX="75" >
                 <path
                     android:name="ellipse_path_1_1"
-                    android:fill="#ff5656ea"
+                    android:fillColor="#ff5656ea"
                     android:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
 
                 <group
@@ -46,7 +42,7 @@
                     android:translateX="25" >
                     <path
                         android:name="ellipse_path_1_2"
-                        android:fill="#ffadadad"
+                        android:fillColor="#ffadadad"
                         android:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
                 </group>
             </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
index f1b2996..4544cae 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
@@ -13,15 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="64"
-        android:viewportWidth="64" />
+        android:viewportWidth="64" >
 
     <group
         android:name="root"
@@ -37,9 +33,9 @@
             android:rotation="0" >
             <path
                 android:name="pie1"
-                android:fill="#00000000"
+                android:fillColor="#00000000"
                 android:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
-                android:stroke="?android:attr/colorControlActivated"
+                android:strokeColor="?android:attr/colorControlActivated"
                 android:strokeLineCap="round"
                 android:strokeLineJoin="miter"
                 android:strokeWidth="2"
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
index 22ce795..0a6cedc 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
@@ -13,19 +13,15 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="24"
-        android:viewportWidth="24" />
+        android:viewportWidth="24" >
 
     <group>
         <path
-            android:fill="#FF000000"
+            android:fillColor="#FF000000"
             android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
index 042173c..94c10df 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
@@ -13,19 +13,15 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="24"
-        android:viewportWidth="24" />
+        android:viewportWidth="24" >
 
     <group>
         <path
-            android:fill="#FF000000"
+            android:fillColor="#FF000000"
             android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
index 6b6f43d..870e508 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
@@ -13,19 +13,15 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="24"
-        android:viewportWidth="24" />
+        android:viewportWidth="24" >
 
     <group>
         <path
-            android:fill="#FF000000"
+            android:fillColor="#FF000000"
             android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
index ba8ebca..8cabca8 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
@@ -13,15 +13,11 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="24"
-        android:viewportWidth="24" />
+        android:viewportWidth="24" >
 
     <group>
         <path
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
index 896a938..7bd6304 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
@@ -13,19 +13,15 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="64dp"
-        android:width="64dp" />
-
-    <viewport
+        android:width="64dp"
         android:viewportHeight="24"
-        android:viewportWidth="24" />
+        android:viewportWidth="24" >
 
     <group>
         <path
-            android:fill="#FF000000"
+            android:fillColor="#FF000000"
             android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" />
     </group>
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
index fc2a15c..dd71ef0 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
@@ -13,23 +13,19 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="128dp"
-        android:width="128dp" />
-
-    <viewport
+        android:width="128dp"
         android:viewportHeight="512"
-        android:viewportWidth="512" />
+        android:viewportWidth="512" >
 
     <group>
         <path
             android:name="002b"
             android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
-            android:stroke="#FF0000FF"
+            android:strokeColor="#FF0000FF"
             android:strokeWidth="4"
-            android:fill="#00000000" />
+            android:fillColor="#00000000" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test02.xml b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
index 9f4abbf..e4f48de 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
@@ -13,23 +13,19 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <size
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:height="128dp"
-        android:width="128dp" />
-
-    <viewport
+        android:width="128dp"
         android:viewportHeight="512"
-        android:viewportWidth="512" />
+        android:viewportWidth="512" >
 
     <group>
         <path
             android:name="002b"
             android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
-            android:stroke="#FF0000FF"
+            android:strokeColor="#FF0000FF"
             android:strokeWidth="4"
-            android:fill="#00000000" />
+            android:fillColor="#00000000" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 5fefab6..ac1ae70 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -4,20 +4,23 @@
 // Android Asset Packaging Tool main entry point.
 //
 #include "ApkBuilder.h"
-#include "Main.h"
 #include "Bundle.h"
+#include "Images.h"
+#include "Main.h"
 #include "ResourceFilter.h"
 #include "ResourceTable.h"
-#include "Images.h"
 #include "XMLNode.h"
 
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <utils/List.h>
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
 
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
 
 using namespace android;
 
@@ -588,6 +591,106 @@
     printf("provides-component:'%s'\n", componentName);
 }
 
+/**
+ * Represents a feature that has been automatically added due to
+ * a pre-requisite or some other reason.
+ */
+struct ImpliedFeature {
+    /**
+     * Name of the implied feature.
+     */
+    String8 name;
+
+    /**
+     * List of human-readable reasons for why this feature was implied.
+     */
+    SortedVector<String8> reasons;
+};
+
+/**
+ * Represents a <feature-group> tag in the AndroidManifest.xml
+ */
+struct FeatureGroup {
+    /**
+     * Human readable label
+     */
+    String8 label;
+
+    /**
+     * Explicit features defined in the group
+     */
+    KeyedVector<String8, bool> features;
+};
+
+static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
+        const char* name, const char* reason) {
+    String8 name8(name);
+    ssize_t idx = impliedFeatures->indexOfKey(name8);
+    if (idx < 0) {
+        idx = impliedFeatures->add(name8, ImpliedFeature());
+        impliedFeatures->editValueAt(idx).name = name8;
+    }
+    impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
+}
+
+static void printFeatureGroup(const FeatureGroup& grp,
+        const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
+    printf("feature-group: label='%s'\n", grp.label.string());
+
+    const size_t numFeatures = grp.features.size();
+    for (size_t i = 0; i < numFeatures; i++) {
+        if (!grp.features[i]) {
+            continue;
+        }
+
+        const String8& featureName = grp.features.keyAt(i);
+        printf("  uses-feature: name='%s'\n",
+                ResTable::normalizeForOutput(featureName.string()).string());
+    }
+
+    const size_t numImpliedFeatures =
+        (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
+    for (size_t i = 0; i < numImpliedFeatures; i++) {
+        const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
+        if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
+            // The feature is explicitly set, no need to use implied
+            // definition.
+            continue;
+        }
+
+        String8 printableFeatureName(ResTable::normalizeForOutput(
+                    impliedFeature.name.string()));
+        printf("  uses-feature: name='%s'\n", printableFeatureName.string());
+        printf("  uses-implied-feature: name='%s' reason='",
+                printableFeatureName.string());
+        const size_t numReasons = impliedFeature.reasons.size();
+        for (size_t j = 0; j < numReasons; j++) {
+            printf("%s", impliedFeature.reasons[j].string());
+            if (j + 2 < numReasons) {
+                printf(", ");
+            } else if (j + 1 < numReasons) {
+                printf(", and ");
+            }
+        }
+        printf("'\n");
+    }
+}
+
+static void addParentFeatures(FeatureGroup* grp, const String8& name) {
+    if (name == "android.hardware.camera.autofocus" ||
+            name == "android.hardware.camera.flash") {
+        grp->features.add(String8("android.hardware.camera"), true);
+    } else if (name == "android.hardware.location.gps" ||
+            name == "android.hardware.location.network") {
+        grp->features.add(String8("android.hardware.location"), true);
+    } else if (name == "android.hardware.touchscreen.multitouch") {
+        grp->features.add(String8("android.hardware.touchscreen"), true);
+    } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
+        grp->features.add(String8("android.hardware.touchscreen.multitouch"), true);
+        grp->features.add(String8("android.hardware.touchscreen"), true);
+    }
+}
+
 /*
  * Handle the "dump" command, to extract select data from an archive.
  */
@@ -797,6 +900,7 @@
             bool isSearchable = false;
             bool withinApplication = false;
             bool withinSupportsInput = false;
+            bool withinFeatureGroup = false;
             bool withinReceiver = false;
             bool withinService = false;
             bool withinProvider = false;
@@ -869,36 +973,7 @@
             // some new uses-feature constants in 2.1 and 2.2. In most cases, the
             // heuristic is "if an app requests a permission but doesn't explicitly
             // request the corresponding <uses-feature>, presume it's there anyway".
-            bool specCameraFeature = false; // camera-related
-            bool specCameraAutofocusFeature = false;
-            bool reqCameraAutofocusFeature = false;
-            bool reqCameraFlashFeature = false;
-            bool hasCameraPermission = false;
-            bool specLocationFeature = false; // location-related
-            bool specNetworkLocFeature = false;
-            bool reqNetworkLocFeature = false;
-            bool specGpsFeature = false;
-            bool reqGpsFeature = false;
-            bool hasMockLocPermission = false;
-            bool hasCoarseLocPermission = false;
-            bool hasGpsPermission = false;
-            bool hasGeneralLocPermission = false;
-            bool specBluetoothFeature = false; // Bluetooth API-related
-            bool hasBluetoothPermission = false;
-            bool specMicrophoneFeature = false; // microphone-related
-            bool hasRecordAudioPermission = false;
-            bool specWiFiFeature = false;
-            bool hasWiFiPermission = false;
-            bool specTelephonyFeature = false; // telephony-related
-            bool reqTelephonySubFeature = false;
-            bool hasTelephonyPermission = false;
-            bool specTouchscreenFeature = false; // touchscreen-related
-            bool specMultitouchFeature = false;
-            bool reqDistinctMultitouchFeature = false;
-            bool specScreenPortraitFeature = false;
-            bool specScreenLandscapeFeature = false;
-            bool reqScreenPortraitFeature = false;
-            bool reqScreenLandscapeFeature = false;
+
             // 2.2 also added some other features that apps can request, but that
             // have no corresponding permission, so we cannot implement any
             // back-compatibility heuristic for them. The below are thus unnecessary
@@ -926,6 +1001,11 @@
             String8 receiverName;
             String8 serviceName;
             Vector<String8> supportedInput;
+
+            FeatureGroup commonFeatures;
+            Vector<FeatureGroup> featureGroups;
+            KeyedVector<String8, ImpliedFeature> impliedFeatures;
+
             while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                 if (code == ResXMLTree::END_TAG) {
                     depth--;
@@ -946,6 +1026,7 @@
                         }
                         withinApplication = false;
                         withinSupportsInput = false;
+                        withinFeatureGroup = false;
                     } else if (depth < 3) {
                         if (withinActivity && isMainActivity) {
                             String8 aName(getComponentName(pkg, activityName));
@@ -1210,59 +1291,27 @@
                                 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
                         largestWidthLimitDp = getIntegerAttribute(tree,
                                 LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
+                    } else if (tag == "feature-group") {
+                        withinFeatureGroup = true;
+                        FeatureGroup group;
+                        group.label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR getting 'android:label' attribute:"
+                                    " %s\n", error.string());
+                            goto bail;
+                        }
+                        featureGroups.add(group);
+
                     } else if (tag == "uses-feature") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
-
                         if (name != "" && error == "") {
                             int req = getIntegerAttribute(tree,
                                     REQUIRED_ATTR, NULL, 1);
 
-                            if (name == "android.hardware.camera") {
-                                specCameraFeature = true;
-                            } else if (name == "android.hardware.camera.autofocus") {
-                                // these have no corresponding permission to check for,
-                                // but should imply the foundational camera permission
-                                reqCameraAutofocusFeature = reqCameraAutofocusFeature || req;
-                                specCameraAutofocusFeature = true;
-                            } else if (req && (name == "android.hardware.camera.flash")) {
-                                // these have no corresponding permission to check for,
-                                // but should imply the foundational camera permission
-                                reqCameraFlashFeature = true;
-                            } else if (name == "android.hardware.location") {
-                                specLocationFeature = true;
-                            } else if (name == "android.hardware.location.network") {
-                                specNetworkLocFeature = true;
-                                reqNetworkLocFeature = reqNetworkLocFeature || req;
-                            } else if (name == "android.hardware.location.gps") {
-                                specGpsFeature = true;
-                                reqGpsFeature = reqGpsFeature || req;
-                            } else if (name == "android.hardware.bluetooth") {
-                                specBluetoothFeature = true;
-                            } else if (name == "android.hardware.touchscreen") {
-                                specTouchscreenFeature = true;
-                            } else if (name == "android.hardware.touchscreen.multitouch") {
-                                specMultitouchFeature = true;
-                            } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
-                                reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req;
-                            } else if (name == "android.hardware.microphone") {
-                                specMicrophoneFeature = true;
-                            } else if (name == "android.hardware.wifi") {
-                                specWiFiFeature = true;
-                            } else if (name == "android.hardware.telephony") {
-                                specTelephonyFeature = true;
-                            } else if (req && (name == "android.hardware.telephony.gsm" ||
-                                               name == "android.hardware.telephony.cdma")) {
-                                // these have no corresponding permission to check for,
-                                // but should imply the foundational telephony permission
-                                reqTelephonySubFeature = true;
-                            } else if (name == "android.hardware.screen.portrait") {
-                                specScreenPortraitFeature = true;
-                            } else if (name == "android.hardware.screen.landscape") {
-                                specScreenLandscapeFeature = true;
+                            commonFeatures.features.add(name, req);
+                            if (req) {
+                                addParentFeatures(&commonFeatures, name);
                             }
-                            printf("uses-feature%s:'%s'\n",
-                                    req ? "" : "-not-required",
-                                            ResTable::normalizeForOutput(name.string()).string());
                         } else {
                             int vers = getIntegerAttribute(tree,
                                     GL_ES_VERSION_ATTR, &error);
@@ -1274,25 +1323,51 @@
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
                         if (name != "" && error == "") {
                             if (name == "android.permission.CAMERA") {
-                                hasCameraPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.feature",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
                             } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
-                                hasGpsPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
+                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
                             } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
-                                hasMockLocPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
                             } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
-                                hasCoarseLocPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
+                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
                             } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
                                        name == "android.permission.INSTALL_LOCATION_PROVIDER") {
-                                hasGeneralLocPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
                             } else if (name == "android.permission.BLUETOOTH" ||
                                        name == "android.permission.BLUETOOTH_ADMIN") {
-                                hasBluetoothPermission = true;
+                                if (targetSdk > 4) {
+                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
+                                            String8::format("requested %s permission", name.string())
+                                            .string());
+                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
+                                            "targetSdkVersion > 4");
+                                }
                             } else if (name == "android.permission.RECORD_AUDIO") {
-                                hasRecordAudioPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
                             } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
                                        name == "android.permission.CHANGE_WIFI_STATE" ||
                                        name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
-                                hasWiFiPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
+                                        String8::format("requested %s permission", name.string())
+                                        .string());
                             } else if (name == "android.permission.CALL_PHONE" ||
                                        name == "android.permission.CALL_PRIVILEGED" ||
                                        name == "android.permission.MODIFY_PHONE_STATE" ||
@@ -1304,7 +1379,8 @@
                                        name == "android.permission.SEND_SMS" ||
                                        name == "android.permission.WRITE_APN_SETTINGS" ||
                                        name == "android.permission.WRITE_SMS") {
-                                hasTelephonyPermission = true;
+                                addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
+                                        String8("requested a telephony permission").string());
                             } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
                                 hasWriteExternalStoragePermission = true;
                             } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
@@ -1430,10 +1506,12 @@
                             if (error == "") {
                                 if (orien == 0 || orien == 6 || orien == 8) {
                                     // Requests landscape, sensorLandscape, or reverseLandscape.
-                                    reqScreenLandscapeFeature = true;
+                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
+                                            "one or more activities have specified a landscape orientation");
                                 } else if (orien == 1 || orien == 7 || orien == 9) {
                                     // Requests portrait, sensorPortrait, or reversePortrait.
-                                    reqScreenPortraitFeature = true;
+                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
+                                            "one or more activities have specified a portrait orientation");
                                 }
                             }
                         } else if (tag == "uses-library") {
@@ -1560,6 +1638,20 @@
                                 goto bail;
                             }
                         }
+                    } else if (withinFeatureGroup && tag == "uses-feature") {
+                        String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+                                    error.string());
+                            goto bail;
+                        }
+
+                        int required = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
+                        FeatureGroup& top = featureGroups.editTop();
+                        top.features.add(name, required);
+                        if (required) {
+                            addParentFeatures(&top, name);
+                        }
                     }
                 } else if (depth == 4) {
                     if (tag == "intent-filter") {
@@ -1734,137 +1826,34 @@
                 }
             }
 
-            /* The following blocks handle printing "inferred" uses-features, based
-             * on whether related features or permissions are used by the app.
-             * Note that the various spec*Feature variables denote whether the
-             * relevant tag was *present* in the AndroidManfest, not that it was
-             * present and set to true.
-             */
-            // Camera-related back-compatibility logic
-            if (!specCameraFeature) {
-                if (reqCameraFlashFeature) {
-                    // if app requested a sub-feature (autofocus or flash) and didn't
-                    // request the base camera feature, we infer that it meant to
-                    printf("uses-feature:'android.hardware.camera'\n");
-                    printf("uses-implied-feature:'android.hardware.camera'," \
-                            "'requested android.hardware.camera.flash feature'\n");
-                } else if (reqCameraAutofocusFeature) {
-                    // if app requested a sub-feature (autofocus or flash) and didn't
-                    // request the base camera feature, we infer that it meant to
-                    printf("uses-feature:'android.hardware.camera'\n");
-                    printf("uses-implied-feature:'android.hardware.camera'," \
-                            "'requested android.hardware.camera.autofocus feature'\n");
-                } else if (hasCameraPermission) {
-                    // if app wants to use camera but didn't request the feature, we infer
-                    // that it meant to, and further that it wants autofocus
-                    // (which was the 1.0 - 1.5 behavior)
-                    printf("uses-feature:'android.hardware.camera'\n");
-                    if (!specCameraAutofocusFeature) {
-                        printf("uses-feature:'android.hardware.camera.autofocus'\n");
-                        printf("uses-implied-feature:'android.hardware.camera.autofocus'," \
-                                "'requested android.permission.CAMERA permission'\n");
+            addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
+                    "default feature for all apps");
+
+            const size_t numFeatureGroups = featureGroups.size();
+            if (numFeatureGroups == 0) {
+                // If no <feature-group> tags were defined, apply auto-implied features.
+                printFeatureGroup(commonFeatures, &impliedFeatures);
+
+            } else {
+                // <feature-group> tags are defined, so we ignore implied features and
+                for (size_t i = 0; i < numFeatureGroups; i++) {
+                    FeatureGroup& grp = featureGroups.editItemAt(i);
+
+                    // Merge the features defined in the top level (not inside a <feature-group>)
+                    // with this feature group.
+                    const size_t numCommonFeatures = commonFeatures.features.size();
+                    for (size_t j = 0; j < numCommonFeatures; j++) {
+                        if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
+                            grp.features.add(commonFeatures.features.keyAt(j), commonFeatures.features[j]);
+                        }
+                    }
+
+                   if (!grp.features.isEmpty()) {
+                        printFeatureGroup(grp);
                     }
                 }
             }
 
-            // Location-related back-compatibility logic
-            if (!specLocationFeature &&
-                (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission ||
-                 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) {
-                // if app either takes a location-related permission or requests one of the
-                // sub-features, we infer that it also meant to request the base location feature
-                printf("uses-feature:'android.hardware.location'\n");
-                printf("uses-implied-feature:'android.hardware.location'," \
-                        "'requested a location access permission'\n");
-            }
-            if (!specGpsFeature && hasGpsPermission) {
-                // if app takes GPS (FINE location) perm but does not request the GPS
-                // feature, we infer that it meant to
-                printf("uses-feature:'android.hardware.location.gps'\n");
-                printf("uses-implied-feature:'android.hardware.location.gps'," \
-                        "'requested android.permission.ACCESS_FINE_LOCATION permission'\n");
-            }
-            if (!specNetworkLocFeature && hasCoarseLocPermission) {
-                // if app takes Network location (COARSE location) perm but does not request the
-                // network location feature, we infer that it meant to
-                printf("uses-feature:'android.hardware.location.network'\n");
-                printf("uses-implied-feature:'android.hardware.location.network'," \
-                        "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n");
-            }
-
-            // Bluetooth-related compatibility logic
-            if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) {
-                // if app takes a Bluetooth permission but does not request the Bluetooth
-                // feature, we infer that it meant to
-                printf("uses-feature:'android.hardware.bluetooth'\n");
-                printf("uses-implied-feature:'android.hardware.bluetooth'," \
-                        "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \
-                        "permission and targetSdkVersion > 4'\n");
-            }
-
-            // Microphone-related compatibility logic
-            if (!specMicrophoneFeature && hasRecordAudioPermission) {
-                // if app takes the record-audio permission but does not request the microphone
-                // feature, we infer that it meant to
-                printf("uses-feature:'android.hardware.microphone'\n");
-                printf("uses-implied-feature:'android.hardware.microphone'," \
-                        "'requested android.permission.RECORD_AUDIO permission'\n");
-            }
-
-            // WiFi-related compatibility logic
-            if (!specWiFiFeature && hasWiFiPermission) {
-                // if app takes one of the WiFi permissions but does not request the WiFi
-                // feature, we infer that it meant to
-                printf("uses-feature:'android.hardware.wifi'\n");
-                printf("uses-implied-feature:'android.hardware.wifi'," \
-                        "'requested android.permission.ACCESS_WIFI_STATE, " \
-                        "android.permission.CHANGE_WIFI_STATE, or " \
-                        "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n");
-            }
-
-            // Telephony-related compatibility logic
-            if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) {
-                // if app takes one of the telephony permissions or requests a sub-feature but
-                // does not request the base telephony feature, we infer that it meant to
-                printf("uses-feature:'android.hardware.telephony'\n");
-                printf("uses-implied-feature:'android.hardware.telephony'," \
-                        "'requested a telephony-related permission or feature'\n");
-            }
-
-            // Touchscreen-related back-compatibility logic
-            if (!specTouchscreenFeature) { // not a typo!
-                // all apps are presumed to require a touchscreen, unless they explicitly say
-                // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
-                // Note that specTouchscreenFeature is true if the tag is present, regardless
-                // of whether its value is true or false, so this is safe
-                printf("uses-feature:'android.hardware.touchscreen'\n");
-                printf("uses-implied-feature:'android.hardware.touchscreen'," \
-                        "'assumed you require a touch screen unless explicitly made optional'\n");
-            }
-            if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
-                // if app takes one of the telephony permissions or requests a sub-feature but
-                // does not request the base telephony feature, we infer that it meant to
-                printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
-                printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \
-                        "'requested android.hardware.touchscreen.multitouch.distinct feature'\n");
-            }
-
-            // Landscape/portrait-related compatibility logic
-            if (!specScreenLandscapeFeature && !specScreenPortraitFeature) {
-                // If the app has specified any activities in its manifest
-                // that request a specific orientation, then assume that
-                // orientation is required.
-                if (reqScreenLandscapeFeature) {
-                    printf("uses-feature:'android.hardware.screen.landscape'\n");
-                    printf("uses-implied-feature:'android.hardware.screen.landscape'," \
-                            "'one or more activities have specified a landscape orientation'\n");
-                }
-                if (reqScreenPortraitFeature) {
-                    printf("uses-feature:'android.hardware.screen.portrait'\n");
-                    printf("uses-implied-feature:'android.hardware.screen.portrait'," \
-                            "'one or more activities have specified a portrait orientation'\n");
-                }
-            }
 
             if (hasWidgetReceivers) {
                 printComponentPresence("app-widget");
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 70a7be8..03b5211 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -619,39 +619,36 @@
             }
 
             if (value != null) {
-                if ((value.getFirst() == ResourceType.STYLE)
-                        || (value.getFirst() == ResourceType.ATTR)) {
-                    // look for the style in the current theme, and its parent:
-                    ResourceValue item = mRenderResources.findItemInTheme(value.getSecond(),
+                if ((value.getFirst() == ResourceType.STYLE)) {
+                    // look for the style in all resources:
+                    StyleResourceValue item = mRenderResources.getStyle(value.getSecond(),
                             isFrameworkRes);
                     if (item != null) {
-                        if (item instanceof StyleResourceValue) {
-                            if (defaultPropMap != null) {
-                                defaultPropMap.put("style", item.getName());
-                            }
-
-                            defStyleValues = (StyleResourceValue)item;
+                        if (defaultPropMap != null) {
+                            defaultPropMap.put("style", item.getName());
                         }
+
+                        defStyleValues = item;
                     } else {
                         Bridge.getLog().error(null,
                                 String.format(
                                         "Style with id 0x%x (resolved to '%s') does not exist.",
                                         defStyleRes, value.getSecond()),
-                                null /*data*/);
+                                null);
                     }
                 } else {
                     Bridge.getLog().error(null,
                             String.format(
-                                    "Resouce id 0x%x is not of type STYLE (instead %s)",
+                                    "Resource id 0x%x is not of type STYLE (instead %s)",
                                     defStyleRes, value.getFirst().toString()),
-                            null /*data*/);
+                            null);
                 }
             } else {
                 Bridge.getLog().error(null,
                         String.format(
                                 "Failed to find style with id 0x%x in current theme",
                                 defStyleRes),
-                        null /*data*/);
+                        null);
             }
         }
 
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index 9ff56d6..99a5671 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -13,7 +13,7 @@
 LOCAL_SRC_FILES := \
 	Main.cpp
 
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
 
 #LOCAL_C_INCLUDES +=
 
@@ -36,7 +36,7 @@
 
 LOCAL_MODULE := pbkdf2gen
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
 LOCAL_SRC_FILES := pbkdf2gen.cpp
 LOCAL_LDLIBS += -ldl
 LOCAL_C_INCLUDES := external/openssl/include $(LOCAL_C_INCLUDES)
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 50fd260..57343c5 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -2,16 +2,20 @@
 
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
 
 import java.util.concurrent.CountDownLatch;
 
@@ -51,12 +55,15 @@
     public static final int RTT_STATUS_ABORTED                  = 8;
 
     public static final int REASON_UNSPECIFIED              = -1;
-    public static final int REASON_INVALID_LISTENER         = -2;
-    public static final int REASON_INVALID_REQUEST          = -3;
+    public static final int REASON_NOT_AVAILABLE            = -2;
+    public static final int REASON_INVALID_LISTENER         = -3;
+    public static final int REASON_INVALID_REQUEST          = -4;
+
+    public static final String DESCRIPTION_KEY  = "android.net.wifi.RttManager.Description";
 
     public class Capabilities {
-        int supportedType;
-        int supportedPeerType;
+        public int supportedType;
+        public int supportedPeerType;
     }
 
     public Capabilities getCapabilities() {
@@ -91,6 +98,73 @@
         public int num_retries;
     }
 
+    /** pseudo-private class used to parcel arguments */
+    public static class ParcelableRttParams implements Parcelable {
+
+        public RttParams mParams[];
+
+        ParcelableRttParams(RttParams[] params) {
+            mParams = params;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            if (mParams != null) {
+                dest.writeInt(mParams.length);
+
+                for (RttParams params : mParams) {
+                    dest.writeInt(params.deviceType);
+                    dest.writeInt(params.requestType);
+                    dest.writeString(params.bssid);
+                    dest.writeInt(params.frequency);
+                    dest.writeInt(params.channelWidth);
+                    dest.writeInt(params.num_samples);
+                    dest.writeInt(params.num_retries);
+                }
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ParcelableRttParams> CREATOR =
+                new Creator<ParcelableRttParams>() {
+                    public ParcelableRttParams createFromParcel(Parcel in) {
+
+                        int num = in.readInt();
+
+                        if (num == 0) {
+                            return new ParcelableRttParams(null);
+                        }
+
+                        RttParams params[] = new RttParams[num];
+                        for (int i = 0; i < num; i++) {
+                            params[i] = new RttParams();
+                            params[i].deviceType = in.readInt();
+                            params[i].requestType = in.readInt();
+                            params[i].bssid = in.readString();
+                            params[i].frequency = in.readInt();
+                            params[i].channelWidth = in.readInt();
+                            params[i].num_samples = in.readInt();
+                            params[i].num_retries = in.readInt();
+
+                        }
+
+                        ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
+                        return parcelableParams;
+                    }
+
+                    public ParcelableRttParams[] newArray(int size) {
+                        return new ParcelableRttParams[size];
+                    }
+                };
+    }
+
     /** specifies RTT results */
     public static class RttResult {
         /** mac address of the device being ranged */
@@ -99,6 +173,9 @@
         /** status of the request */
         public int status;
 
+        /** type of the request used */
+        public int requestType;
+
         /** timestamp of completion, in microsecond since boot */
         public long ts;
 
@@ -121,24 +198,105 @@
         public long rtt_spread_ns;
 
         /** average distance in centimeter, computed based on rtt_ns */
-        public long distance_cm;
+        public int distance_cm;
 
         /** standard deviation observed in distance */
-        public long distance_sd_cm;
+        public int distance_sd_cm;
 
         /** spread (i.e. max - min) distance */
-        public long distance_spread_cm;
+        public int distance_spread_cm;
     }
 
+
+    /** pseudo-private class used to parcel results */
+    public static class ParcelableRttResults implements Parcelable {
+
+        public RttResult mResults[];
+
+        public ParcelableRttResults(RttResult[] results) {
+            mResults = results;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            if (mResults != null) {
+                dest.writeInt(mResults.length);
+                for (RttResult result : mResults) {
+                    dest.writeString(result.bssid);
+                    dest.writeInt(result.status);
+                    dest.writeInt(result.requestType);
+                    dest.writeLong(result.ts);
+                    dest.writeInt(result.rssi);
+                    dest.writeInt(result.rssi_spread);
+                    dest.writeInt(result.tx_rate);
+                    dest.writeLong(result.rtt_ns);
+                    dest.writeLong(result.rtt_sd_ns);
+                    dest.writeLong(result.rtt_spread_ns);
+                    dest.writeInt(result.distance_cm);
+                    dest.writeInt(result.distance_sd_cm);
+                    dest.writeInt(result.distance_spread_cm);
+                }
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ParcelableRttResults> CREATOR =
+                new Creator<ParcelableRttResults>() {
+                    public ParcelableRttResults createFromParcel(Parcel in) {
+
+                        int num = in.readInt();
+
+                        if (num == 0) {
+                            return new ParcelableRttResults(null);
+                        }
+
+                        RttResult results[] = new RttResult[num];
+                        for (int i = 0; i < num; i++) {
+                            results[i] = new RttResult();
+                            results[i].bssid = in.readString();
+                            results[i].status = in.readInt();
+                            results[i].requestType = in.readInt();
+                            results[i].ts = in.readLong();
+                            results[i].rssi = in.readInt();
+                            results[i].rssi_spread = in.readInt();
+                            results[i].tx_rate = in.readInt();
+                            results[i].rtt_ns = in.readLong();
+                            results[i].rtt_sd_ns = in.readLong();
+                            results[i].rtt_spread_ns = in.readLong();
+                            results[i].distance_cm = in.readInt();
+                            results[i].distance_sd_cm = in.readInt();
+                            results[i].distance_spread_cm = in.readInt();
+                        }
+
+                        ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
+                        return parcelableResults;
+                    }
+
+                    public ParcelableRttResults[] newArray(int size) {
+                        return new ParcelableRttResults[size];
+                    }
+                };
+    }
+
+
     public static interface RttListener {
-        public void onSuccess(RttResult results[]);
+        public void onSuccess(RttResult[] results);
         public void onFailure(int reason, String description);
         public void onAborted();
     }
 
-    public void startRanging(RttParams params[], RttListener listener) {
+    public void startRanging(RttParams[] params, RttListener listener) {
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_OP_START_RANGING, 0, removeListener(listener), params);
+        ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
+        sAsyncChannel.sendMessage(CMD_OP_START_RANGING,
+                0, putListener(listener), parcelableParams);
     }
 
     public void stopRanging(RttListener listener) {
@@ -147,11 +305,13 @@
     }
 
     /* private methods */
-    public static final int CMD_OP_START_RANGING        = 0;
-    public static final int CMD_OP_STOP_RANGING         = 1;
-    public static final int CMD_OP_FAILED               = 2;
-    public static final int CMD_OP_SUCCEEDED            = 3;
-    public static final int CMD_OP_ABORTED              = 4;
+    public static final int BASE = Protocol.BASE_WIFI_RTT_MANAGER;
+
+    public static final int CMD_OP_START_RANGING        = BASE + 0;
+    public static final int CMD_OP_STOP_RANGING         = BASE + 1;
+    public static final int CMD_OP_FAILED               = BASE + 2;
+    public static final int CMD_OP_SUCCEEDED            = BASE + 3;
+    public static final int CMD_OP_ABORTED              = BASE + 4;
 
     private Context mContext;
     private IRttManager mService;
@@ -173,7 +333,7 @@
      * Create a new WifiScanner instance.
      * Applications will almost always want to use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
-     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
+     * the standard {@link android.content.Context#WIFI_RTT_SERVICE Context.WIFI_RTT_SERVICE}.
      * @param context the application context
      * @param service the Binder interface
      * @hide
@@ -190,6 +350,7 @@
             if (++sThreadRefCount == 1) {
                 Messenger messenger = null;
                 try {
+                    Log.d(TAG, "Get the messenger from " + mService);
                     messenger = mService.getMessenger();
                 } catch (RemoteException e) {
                     /* do nothing */
@@ -313,10 +474,11 @@
             switch (msg.what) {
                 /* ActionListeners grouped together */
                 case CMD_OP_SUCCEEDED :
-                    ((RttListener) listener).onSuccess((RttResult[])msg.obj);
+                    reportSuccess(listener, msg);
+                    removeListener(msg.arg2);
                     break;
                 case CMD_OP_FAILED :
-                    ((RttListener) listener).onFailure(msg.arg1, (String)msg.obj);
+                    reportFailure(listener, msg);
                     removeListener(msg.arg2);
                     break;
                 case CMD_OP_ABORTED :
@@ -328,6 +490,18 @@
                     return;
             }
         }
+
+        void reportSuccess(Object listener, Message msg) {
+            RttListener rttListener = (RttListener) listener;
+            ParcelableRttResults parcelableResults = (ParcelableRttResults) msg.obj;
+            ((RttListener) listener).onSuccess(parcelableResults.mResults);
+        }
+
+        void reportFailure(Object listener, Message msg) {
+            RttListener rttListener = (RttListener) listener;
+            Bundle bundle = (Bundle) msg.obj;
+            ((RttListener) listener).onFailure(msg.arg1, bundle.getString(DESCRIPTION_KEY));
+        }
     }
 
 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 26a33c1..dd30ac7 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -357,6 +357,7 @@
      * @hide
      * Uid of last app modifying the configuration
      */
+    @SystemApi
     public int lastUpdateUid;
 
     /**