Merge "SurfaceFlinger: Add sourceCrop to screenshot"
diff --git a/Android.mk b/Android.mk
index d45189e..c58ef53 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,6 +78,7 @@
 	core/java/android/app/IServiceConnection.aidl \
 	core/java/android/app/IStopUserCallback.aidl \
 	core/java/android/app/task/ITaskCallback.aidl \
+	core/java/android/app/task/ITaskManager.aidl \
 	core/java/android/app/task/ITaskService.aidl \
 	core/java/android/app/IThumbnailRetriever.aidl \
 	core/java/android/app/ITransientNotification.aidl \
@@ -216,6 +217,8 @@
 	core/java/android/service/wallpaper/IWallpaperEngine.aidl \
 	core/java/android/service/wallpaper/IWallpaperService.aidl \
 	core/java/android/tv/ITvInputClient.aidl \
+	core/java/android/tv/ITvInputHardware.aidl \
+	core/java/android/tv/ITvInputHardwareCallback.aidl \
 	core/java/android/tv/ITvInputManager.aidl \
 	core/java/android/tv/ITvInputService.aidl \
 	core/java/android/tv/ITvInputServiceCallback.aidl \
@@ -378,55 +381,14 @@
 LOCAL_STATIC_JAVA_LIBRARIES := framework-base
 LOCAL_DX_FLAGS := --core-library
 
-# Packages to include, use \* wildcard to include descendants.
+# List of packages to include along with their descendants.
 LOCAL_JAR_PACKAGES := \
-	android \
-	android.accessibilityservice\* \
-	android.accounts\* \
-	android.alsa\* \
-	android.animation\* \
-	android.annotation\* \
-	android.app\* \
-	android.appwidget\* \
-	android.bluetooth\* \
-	android.content\* \
-	android.content\* \
-	android.database\* \
-	android.ddm\* \
-	android.drm\* \
-	android.emoji\* \
-	android.filterfw\* \
-	android.filterpacks\* \
-	android.gesture\* \
-	android.graphics\* \
-	android.inputmethodservice\* \
-	android.location\* \
-	android.media\* \
-	android.mtp\* \
-	android.net\* \
-	android.nfc\* \
-	android.opengl\* \
-	android.os\* \
-	android.preference\* \
-	android.print\* \
-	android.printservice\* \
-	android.provider\* \
-	android.renderscript\* \
-	android.sax\* \
-	android.security\* \
-	android.service\* \
-	android.speech\* \
-	android.system\* \
-	android.telecomm\* \
-	android.telephony\* \
-	android.test\* \
-	android.text\* \
-	android.transition\* \
-	android.tv\* \
-	android.util\* \
-	android.view\* \
-	android.webkit\* \
-	android.widget\*
+    android
+
+# List of packages to exclude along with their descendants.
+# Overrides inclusion.
+LOCAL_JAR_EXCLUDE_PACKAGES := \
+    android.hardware
 
 # List of classes and interfaces which should be loaded by the Zygote.
 LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes
@@ -444,16 +406,11 @@
 LOCAL_STATIC_JAVA_LIBRARIES := framework-base
 LOCAL_DX_FLAGS := --core-library
 
-# Packages to include, use \* wildcard to include descendants.
-# 'android' is required to be able to include 'android.hardware',
-# however, it causes classes in 'android' to be part of framework
-# and framework2.
-# TODO: Finer grained matching.
+# List of packages to include along with their descendants.
 LOCAL_JAR_PACKAGES := \
-	android \
-	android.hardware\* \
-	com\* \
-	javax\*
+    android.hardware \
+    com \
+    javax
 
 include $(BUILD_JAVA_LIBRARY)
 framework2_module := $(LOCAL_INSTALLED_MODULE)
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c841338..48a20a4 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -191,6 +191,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.txt b/api/current.txt
index 3f5a090..c4ad5a9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4691,6 +4691,7 @@
     method public android.app.Notification.WearableExtender setHintShowBackgroundOnly(boolean);
     method public android.app.Notification.WearableExtender setStartScrollBottom(boolean);
     field public static final int SIZE_DEFAULT = 0; // 0x0
+    field public static final int SIZE_FULL_SCREEN = 5; // 0x5
     field public static final int SIZE_LARGE = 4; // 0x4
     field public static final int SIZE_MEDIUM = 3; // 0x3
     field public static final int SIZE_SMALL = 2; // 0x2
@@ -5154,10 +5155,10 @@
   }
 
   public class DevicePolicyManager {
-    method public void addForwardingIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
+    method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
-    method public void clearForwardingIntentFilters(android.content.ComponentName);
+    method public void clearCrossProfileIntentFilters(android.content.ComponentName);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
     method public android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
@@ -5232,8 +5233,8 @@
     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 = "defaultManagedProfileName";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "deviceAdminPackageName";
-    field public static int FLAG_TO_MANAGED_PROFILE;
-    field public static int FLAG_TO_PRIMARY_USER;
+    field public static int FLAG_MANAGED_CAN_ACCESS_PARENT;
+    field public static int FLAG_PARENT_CAN_ACCESS_MANAGED;
     field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
     field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
     field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
@@ -5352,6 +5353,58 @@
 
 package android.app.task {
 
+  public class Task implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getBackoffPolicy();
+    method public android.os.Bundle getExtras();
+    method public int getId();
+    method public long getInitialBackoffMillis();
+    method public long getIntervalMillis();
+    method public long getMaxExecutionDelayMillis();
+    method public long getMinLatencyMillis();
+    method public int getNetworkCapabilities();
+    method public android.content.ComponentName getService();
+    method public boolean isPeriodic();
+    method public boolean isRequireCharging();
+    method public boolean isRequireDeviceIdle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static abstract interface Task.BackoffPolicy {
+    field public static final int EXPONENTIAL = 1; // 0x1
+    field public static final int LINEAR = 0; // 0x0
+  }
+
+  public static final class Task.Builder {
+    ctor public Task.Builder(int, android.content.ComponentName);
+    method public android.app.task.Task build();
+    method public android.app.task.Task.Builder setBackoffCriteria(long, int);
+    method public android.app.task.Task.Builder setExtras(android.os.Bundle);
+    method public android.app.task.Task.Builder setMinimumLatency(long);
+    method public android.app.task.Task.Builder setOverrideDeadline(long);
+    method public android.app.task.Task.Builder setPeriodic(long);
+    method public android.app.task.Task.Builder setRequiredNetworkCapabilities(int);
+    method public android.app.task.Task.Builder setRequiresCharging(boolean);
+    method public android.app.task.Task.Builder setRequiresDeviceIdle(boolean);
+  }
+
+  public static abstract interface Task.NetworkType {
+    field public static final int ANY = 1; // 0x1
+    field public static final int NONE = 0; // 0x0
+    field public static final int UNMETERED = 2; // 0x2
+  }
+
+  public abstract class TaskManager {
+    ctor public TaskManager();
+    method public abstract void cancel(int);
+    method public abstract void cancelAll();
+    method public abstract java.util.List<android.app.task.Task> getAllPendingTasks();
+    method public abstract int schedule(android.app.task.Task);
+    field public static final int RESULT_FAILURE = 0; // 0x0
+    field public static final int RESULT_SUCCESS = 1; // 0x1
+  }
+
   public class TaskParams implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.Bundle getExtras();
@@ -6975,6 +7028,7 @@
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String TASK_SERVICE = "task";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
@@ -7913,55 +7967,6 @@
     method public abstract void onStatusChanged(int);
   }
 
-  public class Task implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getBackoffPolicy();
-    method public android.os.Bundle getExtras();
-    method public long getInitialBackoffMillis();
-    method public long getIntervalMillis();
-    method public long getMaxExecutionDelayMillis();
-    method public long getMinLatencyMillis();
-    method public int getNetworkCapabilities();
-    method public android.content.ComponentName getService();
-    method public int getTaskId();
-    method public boolean isPeriodic();
-    method public boolean isRequireCharging();
-    method public boolean isRequireDeviceIdle();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public static abstract interface Task.BackoffPolicy {
-    field public static final int EXPONENTIAL = 1; // 0x1
-    field public static final int LINEAR = 0; // 0x0
-  }
-
-  public final class Task.Builder {
-    ctor public Task.Builder(int, android.content.ComponentName);
-    method public android.content.Task build();
-    method public android.content.Task.Builder setBackoffCriteria(long, int);
-    method public android.content.Task.Builder setExtras(android.os.Bundle);
-    method public android.content.Task.Builder setMinimumLatency(long);
-    method public android.content.Task.Builder setOverrideDeadline(long);
-    method public android.content.Task.Builder setPeriodic(long);
-    method public android.content.Task.Builder setRequiredNetworkCapabilities(int);
-    method public android.content.Task.Builder setRequiresCharging(boolean);
-    method public android.content.Task.Builder setRequiresDeviceIdle(boolean);
-  }
-
-  public static abstract interface Task.NetworkType {
-    field public static final int ANY = 0; // 0x0
-    field public static final int UNMETERED = 1; // 0x1
-  }
-
-  public abstract class TaskManager {
-    ctor public TaskManager();
-    method public abstract void cancel(int);
-    method public abstract void cancelAll();
-    method public abstract java.util.List<android.content.Task> getAllPendingTasks();
-    method public abstract int schedule(android.content.Task);
-  }
-
   public class UriMatcher {
     ctor public UriMatcher(int);
     method public void addURI(java.lang.String, java.lang.String, int);
@@ -11930,6 +11935,7 @@
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
+    method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
     method public java.lang.String getName();
@@ -11939,6 +11945,9 @@
     method public int getType();
     method public java.lang.String getVendor();
     method public int getVersion();
+    method public boolean isWakeUpSensor();
+    field public static final java.lang.String SENSOR_STRING_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR = "android.sensor.non_wake_up_proximity_sensor";
+    field public static final java.lang.String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR = "android.sensor.wake_up_tilt_detector";
     field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
     field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
     field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
@@ -11960,6 +11969,24 @@
     field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
     field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
     field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_ACCELEROMETER = "android.sensor.wake_up_accelerometer";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_AMBIENT_TEMPERATURE = "android.sensor.wake_up_ambient_temperature";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_GAME_ROTATION_VECTOR = "android.sensor.wake_up_game_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.wake_up_geomagnetic_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_GRAVITY = "android.sensor.wake_up_gravity";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_GYROSCOPE = "android.sensor.wake_up_gyroscope";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED = "android.sensor.wake_up_gyroscope_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_HEART_RATE = "android.sensor.wake_up_heart_rate";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_LIGHT = "android.sensor.wake_up_light";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_LINEAR_ACCELERATION = "android.sensor.wake_up_linear_acceleration";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_MAGNETIC_FIELD = "android.sensor.wake_up_magnetic_field";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.wake_up_magnetic_field_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_ORIENTATION = "android.sensor.wake_up_orientation";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_PRESSURE = "android.sensor.wake_up_pressure";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_RELATIVE_HUMIDITY = "android.sensor.wake_up_relative_humidity";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_ROTATION_VECTOR = "android.sensor.wake_up_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_STEP_COUNTER = "android.sensor.wake_up_step_counter";
+    field public static final java.lang.String STRING_TYPE_WAKE_UP_STEP_DETECTOR = "android.sensor.wake_up_step_detector";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -11973,6 +12000,7 @@
     field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
     field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
+    field public static final int TYPE_NON_WAKE_UP_PROXIMITY_SENSOR = 22; // 0x16
     field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
     field public static final int TYPE_PRESSURE = 6; // 0x6
     field public static final int TYPE_PROXIMITY = 8; // 0x8
@@ -11982,6 +12010,25 @@
     field public static final int TYPE_STEP_COUNTER = 19; // 0x13
     field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
+    field public static final int TYPE_WAKE_UP_ACCELEROMETER = 23; // 0x17
+    field public static final int TYPE_WAKE_UP_AMBIENT_TEMPERATURE = 33; // 0x21
+    field public static final int TYPE_WAKE_UP_GAME_ROTATION_VECTOR = 35; // 0x23
+    field public static final int TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR = 39; // 0x27
+    field public static final int TYPE_WAKE_UP_GRAVITY = 29; // 0x1d
+    field public static final int TYPE_WAKE_UP_GYROSCOPE = 26; // 0x1a
+    field public static final int TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED = 36; // 0x24
+    field public static final int TYPE_WAKE_UP_HEART_RATE = 40; // 0x28
+    field public static final int TYPE_WAKE_UP_LIGHT = 27; // 0x1b
+    field public static final int TYPE_WAKE_UP_LINEAR_ACCELERATION = 30; // 0x1e
+    field public static final int TYPE_WAKE_UP_MAGNETIC_FIELD = 24; // 0x18
+    field public static final int TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED = 34; // 0x22
+    field public static final int TYPE_WAKE_UP_ORIENTATION = 25; // 0x19
+    field public static final int TYPE_WAKE_UP_PRESSURE = 28; // 0x1c
+    field public static final int TYPE_WAKE_UP_RELATIVE_HUMIDITY = 32; // 0x20
+    field public static final int TYPE_WAKE_UP_ROTATION_VECTOR = 31; // 0x1f
+    field public static final int TYPE_WAKE_UP_STEP_COUNTER = 38; // 0x26
+    field public static final int TYPE_WAKE_UP_STEP_DETECTOR = 37; // 0x25
+    field public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41; // 0x29
   }
 
   public class SensorEvent {
@@ -12083,6 +12130,7 @@
     field public static final int SENSOR_STATUS_ACCURACY_HIGH = 3; // 0x3
     field public static final int SENSOR_STATUS_ACCURACY_LOW = 1; // 0x1
     field public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2; // 0x2
+    field public static final int SENSOR_STATUS_NO_CONTACT = -1; // 0xffffffff
     field public static final int SENSOR_STATUS_UNRELIABLE = 0; // 0x0
     field public static final deprecated int SENSOR_TEMPERATURE = 4; // 0x4
     field public static final deprecated int SENSOR_TRICORDER = 64; // 0x40
@@ -12129,9 +12177,11 @@
 
   public static abstract class CameraCaptureSession.CaptureListener {
     ctor public CameraCaptureSession.CaptureListener();
-    method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
+    method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult);
     method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure);
-    method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraDevice, int, int);
+    method public void onCaptureProgressed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
+    method public void onCaptureSequenceAborted(android.hardware.camera2.CameraDevice, int);
+    method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraDevice, int, long);
     method public void onCaptureStarted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, long);
   }
 
@@ -12145,70 +12195,75 @@
   }
 
   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
-    method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureRequestKeys();
-    method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureResultKeys();
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_RANGE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_STEP;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_AVAILABLE_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_EFFECTS;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_SCENE_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_AVAILABLE_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MAX_REGIONS;
-    field public static final android.hardware.camera2.CameraMetadata.Key EDGE_AVAILABLE_EDGE_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_INFO_AVAILABLE;
-    field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key INFO_SUPPORTED_HARDWARE_LEVEL;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_AVAILABLE_THUMBNAIL_SIZES;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FACING;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_APERTURES;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_HYPERFOCAL_DISTANCE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_SHADING_MAP_SIZE;
-    field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_AVAILABLE_CAPABILITIES;
-    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_INPUT_STREAMS;
-    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
-    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT;
-    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH;
-    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
-    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROPPING_TYPE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_STREAM_CONFIGURATION_MAP;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BLACK_LEVEL_PATTERN;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_CALIBRATION_TRANSFORM1;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_CALIBRATION_TRANSFORM2;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_COLOR_TRANSFORM1;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_COLOR_TRANSFORM2;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX1;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX2;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_EXPOSURE_TIME_RANGE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_MAX_FRAME_DURATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PHYSICAL_SIZE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PIXEL_ARRAY_SIZE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_SENSITIVITY_RANGE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_WHITE_LEVEL;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT1;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT2;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_MAX_FACE_COUNT;
-    field public static final android.hardware.camera2.CameraMetadata.Key SYNC_MAX_LATENCY;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_AVAILABLE_TONE_MAP_MODES;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MAX_CURVE_POINTS;
+    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
+    method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
+    method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_COMPENSATION_RANGE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_COMPENSATION_STEP;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AF_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_EFFECTS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_SCENE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AWB_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key EDGE_AVAILABLE_EDGE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key FLASH_INFO_AVAILABLE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key INFO_SUPPORTED_HARDWARE_LEVEL;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key JPEG_AVAILABLE_THUMBNAIL_SIZES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_FACING;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_APERTURES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_HYPERFOCAL_DISTANCE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_SHADING_MAP_SIZE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_AVAILABLE_CAPABILITIES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_INPUT_STREAMS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PARTIAL_RESULT_COUNT;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PIPELINE_MAX_DEPTH;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_CROPPING_TYPE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_STREAM_CONFIGURATION_MAP;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_BLACK_LEVEL_PATTERN;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_CALIBRATION_TRANSFORM1;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_CALIBRATION_TRANSFORM2;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_COLOR_TRANSFORM1;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_COLOR_TRANSFORM2;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_FORWARD_MATRIX1;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_FORWARD_MATRIX2;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_EXPOSURE_TIME_RANGE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_MAX_FRAME_DURATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PHYSICAL_SIZE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PIXEL_ARRAY_SIZE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_SENSITIVITY_RANGE;
+    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_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;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_MAX_FACE_COUNT;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SYNC_MAX_LATENCY;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key TONEMAP_AVAILABLE_TONE_MAP_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key TONEMAP_MAX_CURVE_POINTS;
+  }
+
+  public static final class CameraCharacteristics.Key {
+    method public final boolean equals(java.lang.Object);
+    method public java.lang.String getName();
+    method public final int hashCode();
   }
 
   public abstract interface CameraDevice implements java.lang.AutoCloseable {
@@ -12233,9 +12288,11 @@
 
   public static abstract deprecated class CameraDevice.CaptureListener {
     ctor public CameraDevice.CaptureListener();
-    method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
+    method public void onCaptureCompleted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult);
     method public void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure);
-    method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraDevice, int, int);
+    method public void onCaptureProgressed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
+    method public void onCaptureSequenceAborted(android.hardware.camera2.CameraDevice, int);
+    method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraDevice, int, long);
     method public void onCaptureStarted(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, long);
   }
 
@@ -12271,8 +12328,7 @@
   }
 
   public abstract class CameraMetadata {
-    method public abstract T get(android.hardware.camera2.CameraMetadata.Key<T>);
-    method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getKeys();
+    method public java.util.List<TKey> getKeys();
     field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
     field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
@@ -12442,12 +12498,6 @@
     field public static final int TONEMAP_MODE_HIGH_QUALITY = 2; // 0x2
   }
 
-  public static class CameraMetadata.Key {
-    method public final boolean equals(java.lang.Object);
-    method public final java.lang.String getName();
-    method public final int hashCode();
-  }
-
   public class CaptureFailure {
     method public int getFrameNumber();
     method public int getReason();
@@ -12460,146 +12510,174 @@
 
   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
     method public int describeContents();
-    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public java.lang.Object getTag();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
-    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
-    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key BLACK_LEVEL_LOCK;
+    field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_GAINS;
+    field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_TRANSFORM;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_ANTIBANDING_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_EXPOSURE_COMPENSATION;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_LOCK;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_PRECAPTURE_TRIGGER;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_REGIONS;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_TARGET_FPS_RANGE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_REGIONS;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_TRIGGER;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_LOCK;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_REGIONS;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_CAPTURE_INTENT;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_EFFECT_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_SCENE_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_ORIENTATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_QUALITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_QUALITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_SIZE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_APERTURE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FILTER_DENSITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCAL_LENGTH;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_DISTANCE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_OPTICAL_STABILIZATION_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key EDGE_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key FLASH_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key HOT_PIXEL_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_COORDINATES;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_PROCESSING_METHOD;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_TIMESTAMP;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_ORIENTATION;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_QUALITY;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_THUMBNAIL_QUALITY;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_THUMBNAIL_SIZE;
+    field public static final android.hardware.camera2.CaptureRequest.Key LENS_APERTURE;
+    field public static final android.hardware.camera2.CaptureRequest.Key LENS_FILTER_DENSITY;
+    field public static final android.hardware.camera2.CaptureRequest.Key LENS_FOCAL_LENGTH;
+    field public static final android.hardware.camera2.CaptureRequest.Key LENS_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CaptureRequest.Key LENS_OPTICAL_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key SCALER_CROP_REGION;
+    field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_EXPOSURE_TIME;
+    field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_FRAME_DURATION;
+    field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_SENSITIVITY;
+    field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_TEST_PATTERN_DATA;
+    field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_TEST_PATTERN_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key SHADING_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_FACE_DETECT_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_HOT_PIXEL_MAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_LENS_SHADING_MAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_BLUE;
+    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_GREEN;
+    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_RED;
+    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_MODE;
   }
 
   public static final class CaptureRequest.Builder {
     method public void addTarget(android.view.Surface);
     method public android.hardware.camera2.CaptureRequest build();
-    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public void removeTarget(android.view.Surface);
-    method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T);
+    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
     method public void setTag(java.lang.Object);
   }
 
-  public final class CaptureResult extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+  public static final class CaptureRequest.Key {
+    method public final boolean equals(java.lang.Object);
+    method public java.lang.String getName();
+    method public final int hashCode();
+  }
+
+  public class CaptureResult extends android.hardware.camera2.CameraMetadata {
+    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
     method public int getFrameNumber();
     method public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
-    field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
-    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
-    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_STATE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_STATE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_STATE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE;
-    field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_ORIENTATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_QUALITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_QUALITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key JPEG_THUMBNAIL_SIZE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_APERTURE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FILTER_DENSITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCAL_LENGTH;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_DISTANCE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_FOCUS_RANGE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_OPTICAL_STABILIZATION_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key LENS_STATE;
-    field public static final android.hardware.camera2.CameraMetadata.Key NOISE_REDUCTION_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_FRAME_COUNT;
-    field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_DEPTH;
-    field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
-    field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_SCENE_FLICKER;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED;
-    field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key BLACK_LEVEL_LOCK;
+    field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_GAINS;
+    field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_TRANSFORM;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_ANTIBANDING_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_EXPOSURE_COMPENSATION;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_LOCK;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_PRECAPTURE_TRIGGER;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_REGIONS;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_STATE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_TARGET_FPS_RANGE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_REGIONS;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_STATE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_TRIGGER;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_LOCK;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_REGIONS;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_STATE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_CAPTURE_INTENT;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_EFFECT_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_SCENE_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key CONTROL_VIDEO_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key EDGE_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key FLASH_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key FLASH_STATE;
+    field public static final android.hardware.camera2.CaptureResult.Key HOT_PIXEL_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_COORDINATES;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_PROCESSING_METHOD;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_TIMESTAMP;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_ORIENTATION;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_QUALITY;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_QUALITY;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_SIZE;
+    field public static final android.hardware.camera2.CaptureResult.Key LENS_APERTURE;
+    field public static final android.hardware.camera2.CaptureResult.Key LENS_FILTER_DENSITY;
+    field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCAL_LENGTH;
+    field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCUS_RANGE;
+    field public static final android.hardware.camera2.CaptureResult.Key LENS_OPTICAL_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key LENS_STATE;
+    field public static final android.hardware.camera2.CaptureResult.Key NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key REQUEST_FRAME_COUNT;
+    field public static final android.hardware.camera2.CaptureResult.Key REQUEST_PIPELINE_DEPTH;
+    field public static final android.hardware.camera2.CaptureResult.Key SCALER_CROP_REGION;
+    field public static final android.hardware.camera2.CaptureResult.Key SENSOR_EXPOSURE_TIME;
+    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_SENSITIVITY;
+    field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA;
+    field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TIMESTAMP;
+    field public static final android.hardware.camera2.CaptureResult.Key SHADING_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_FACES;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_FACE_DETECT_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_MAP;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_MAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_SCENE_FLICKER;
+    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_BLUE;
+    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_GREEN;
+    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_RED;
+    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_MODE;
+  }
+
+  public static final class CaptureResult.Key {
+    method public final boolean equals(java.lang.Object);
+    method public java.lang.String getName();
+    method public final int hashCode();
+  }
+
+  public final class DngCreator implements java.lang.AutoCloseable {
+    ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult);
+    method public void close();
+    method public android.hardware.camera2.DngCreator setDescription(java.lang.String);
+    method public android.hardware.camera2.DngCreator setLocation(android.location.Location);
+    method public android.hardware.camera2.DngCreator setOrientation(int);
+    method public android.hardware.camera2.DngCreator setThumbnail(android.graphics.Bitmap);
+    method public android.hardware.camera2.DngCreator setThumbnail(android.media.Image);
+    method public void writeByteBuffer(java.io.OutputStream, android.util.Size, java.nio.ByteBuffer, long) throws java.io.IOException;
+    method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException;
+    method public void writeInputStream(java.io.OutputStream, android.util.Size, java.io.InputStream, long) throws java.io.IOException;
+  }
+
+  public final class TotalCaptureResult extends android.hardware.camera2.CaptureResult {
+    method public java.util.List<android.hardware.camera2.CaptureResult> getPartialResults();
   }
 
 }
@@ -13738,7 +13816,6 @@
   }
 
   public class AudioFormat {
-    ctor public AudioFormat();
     field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
     field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
     field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -14070,19 +14147,6 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
-  public final class DngCreator implements java.lang.AutoCloseable {
-    ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult);
-    method public void close();
-    method public android.media.DngCreator setDescription(java.lang.String);
-    method public android.media.DngCreator setLocation(android.location.Location);
-    method public android.media.DngCreator setOrientation(int);
-    method public android.media.DngCreator setThumbnail(android.graphics.Bitmap);
-    method public android.media.DngCreator setThumbnail(android.media.Image);
-    method public void writeByteBuffer(java.io.OutputStream, android.util.Size, java.nio.ByteBuffer, long) throws java.io.IOException;
-    method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException;
-    method public void writeInputStream(java.io.OutputStream, android.util.Size, java.io.InputStream, long) throws java.io.IOException;
-  }
-
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
     method public double getAltitude(double);
@@ -17526,13 +17590,10 @@
   public class WifiPasspointCredential implements android.os.Parcelable {
     ctor public WifiPasspointCredential(java.lang.String, java.lang.String, android.net.wifi.WifiEnterpriseConfig);
     method public int describeContents();
-    method public java.lang.String getCaRootCertPath();
-    method public java.lang.String getClientCertPath();
-    method public int getEapMethod();
+    method public android.net.wifi.WifiEnterpriseConfig getEnterpriseConfig();
     method public java.lang.String getFqdn();
     method public java.lang.String getRealm();
-    method public java.lang.String getUserName();
-    method public void setCredential(android.net.wifi.WifiEnterpriseConfig);
+    method public void setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
     method public void setFqdn(java.lang.String);
     method public void setRealm(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
@@ -28197,12 +28258,8 @@
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
     method public boolean hasIccCard();
-    method public boolean iccCloseLogicalChannel(int);
-    method public int iccOpenLogicalChannel(java.lang.String);
-    method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isNetworkRoaming();
     method public void listen(android.telephony.PhoneStateListener, int);
-    method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final int CALL_STATE_IDLE = 0; // 0x0
diff --git a/api/removed.txt b/api/removed.txt
index e69de29..458c422 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -0,0 +1,8 @@
+package android.media {
+
+  public class AudioFormat {
+    ctor public AudioFormat();
+  }
+
+}
+
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 5454b46..b7c2c22 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1146,12 +1146,22 @@
     }
 
     private void runUninstall() {
-        int unInstallFlags = PackageManager.DELETE_ALL_USERS;
+        int unInstallFlags = 0;
+        int userId = UserHandle.USER_ALL;
 
         String opt;
         while ((opt=nextOption()) != null) {
             if (opt.equals("-k")) {
                 unInstallFlags |= PackageManager.DELETE_KEEP_DATA;
+            } else if (opt.equals("--user")) {
+                String param = nextArg();
+                if (isNumber(param)) {
+                    userId = Integer.parseInt(param);
+                } else {
+                    showUsage();
+                    System.err.println("Error: Invalid user: " + param);
+                    return;
+                }
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
@@ -1164,7 +1174,34 @@
             showUsage();
             return;
         }
-        boolean result = deletePackage(pkg, unInstallFlags);
+
+        if (userId == UserHandle.USER_ALL) {
+            userId = UserHandle.USER_OWNER;
+            unInstallFlags |= PackageManager.DELETE_ALL_USERS;
+        } else {
+            PackageInfo info;
+            try {
+                info = mPm.getPackageInfo(pkg, 0, userId);
+            } catch (RemoteException e) {
+                System.err.println(e.toString());
+                System.err.println(PM_NOT_RUNNING_ERR);
+                return;
+            }
+            if (info == null) {
+                System.err.println("Failure - not installed for " + userId);
+                return;
+            }
+            final boolean isSystem =
+                    (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+            // If we are being asked to delete a system app for just one
+            // user set flag so it disables rather than reverting to system
+            // version of the app.
+            if (isSystem) {
+                unInstallFlags |= PackageManager.DELETE_SYSTEM_APP;
+            }
+        }
+
+        boolean result = deletePackage(pkg, unInstallFlags, userId);
         if (result) {
             System.out.println("Success");
         } else {
@@ -1172,10 +1209,10 @@
         }
     }
 
-    private boolean deletePackage(String pkg, int unInstallFlags) {
+    private boolean deletePackage(String pkg, int unInstallFlags, int userId) {
         PackageDeleteObserver obs = new PackageDeleteObserver();
         try {
-            mPm.deletePackageAsUser(pkg, obs, UserHandle.USER_OWNER, unInstallFlags);
+            mPm.deletePackageAsUser(pkg, obs, userId, unInstallFlags);
 
             synchronized (obs) {
                 while (!obs.finished) {
@@ -1571,7 +1608,7 @@
         System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
         System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
         System.err.println("                  [--originating-uri <URI>] [--referrer <URI>] PATH");
-        System.err.println("       pm uninstall [-k] PACKAGE");
+        System.err.println("       pm uninstall [-k] [--user USER_ID] PACKAGE");
         System.err.println("       pm clear [--user USER_ID] PACKAGE");
         System.err.println("       pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
@@ -1585,7 +1622,7 @@
         System.err.println("       pm get-install-location");
         System.err.println("       pm set-permission-enforced PERMISSION [true|false]");
         System.err.println("       pm trim-caches DESIRED_FREE_SPACE");
-        System.err.println("       pm create-user [--relatedTo USER_ID] [--managed] USER_NAME");
+        System.err.println("       pm create-user [--profileOf USER_ID] [--managed] USER_NAME");
         System.err.println("       pm remove-user USER_ID");
         System.err.println("       pm get-max-users");
         System.err.println("");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 07de85c..b5281ff 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4194,7 +4194,11 @@
      */
     public void startActivityFromFragment(@NonNull Fragment fragment, Intent intent,
             int requestCode) {
-        startActivityFromFragment(fragment, intent, requestCode, null);
+        Bundle options = null;
+        if (mWindow.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+            options = ActivityOptions.makeSceneTransitionAnimation(this).toBundle();
+        }
+        startActivityFromFragment(fragment, intent, requestCode, options);
     }
 
     /**
@@ -4219,6 +4223,9 @@
      */
     public void startActivityFromFragment(@NonNull Fragment fragment, Intent intent,
             int requestCode, @Nullable Bundle options) {
+        if (options != null) {
+            mActivityTransitionState.startExitOutTransition(this, options);
+        }
         Instrumentation.ActivityResult ar =
             mInstrumentation.execStartActivity(
                 this, mMainThread.getApplicationThread(), mToken, fragment,
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 2f35160..84673d9 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1455,10 +1455,10 @@
      * @hide
      */
     @Override
-    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
-            int userIdDest) {
+    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
+            int sourceUserId, int targetUserId) {
         try {
-            mPM.addForwardingIntentFilter(filter, removable, userIdOrig, userIdDest);
+            mPM.addCrossProfileIntentFilter(filter, removable, sourceUserId, targetUserId);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1468,14 +1468,31 @@
      * @hide
      */
     @Override
-    public void clearForwardingIntentFilters(int userIdOrig) {
+    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int sourceUserId,
+            int targetUserId) {
+        addCrossProfileIntentFilter(filter, removable, sourceUserId, targetUserId);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearCrossProfileIntentFilters(int sourceUserId) {
         try {
-            mPM.clearForwardingIntentFilters(userIdOrig);
+            mPM.clearCrossProfileIntentFilters(sourceUserId);
         } catch (RemoteException e) {
             // Should never happen!
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public void clearForwardingIntentFilters(int sourceUserId) {
+        clearCrossProfileIntentFilters(sourceUserId);
+    }
+
     private final ContextImpl mContext;
     private final IPackageManager mPM;
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1634d11..ff8688d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -133,10 +133,12 @@
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.app.admin.DevicePolicyManager;
+import android.app.task.ITaskManager;
 import android.app.trust.TrustManager;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.appwidget.IAppWidgetService.Stub;
 import com.android.internal.os.IDropBoxManagerService;
 
 import java.io.File;
@@ -693,6 +695,12 @@
                 public Object createService(ContextImpl ctx) {
                 return new UsageStatsManager(ctx.getOuterContext());
         }});
+
+        registerService(TASK_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(TASK_SERVICE);
+                return new TaskManagerImpl(ITaskManager.Stub.asInterface(b));
+            }});
     }
 
     static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6e23b11..25f24b1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -989,10 +989,9 @@
          * <pre class="prettyprint">
          * Notification.Action action = new Notification.Action.Builder(
          *         R.drawable.archive_all, "Archive all", actionIntent)
-         *         .apply(new Notification.Action.WearableExtender()
+         *         .extend(new Notification.Action.WearableExtender()
          *                 .setAvailableOffline(false))
-         *         .build();
-         * </pre>
+         *         .build();</pre>
          */
         public static final class WearableExtender implements Extender {
             /** Notification action extra which contains wearable extensions */
@@ -3307,8 +3306,7 @@
      * <pre class="prettyprint">
      * Notification.WearableExtender wearableExtender = new Notification.WearableExtender(
      *         notification);
-     * List&lt;Notification&gt; pages = wearableExtender.getPages();
-     * </pre>
+     * List&lt;Notification&gt; pages = wearableExtender.getPages();</pre>
      */
     public static final class WearableExtender implements Extender {
         /**
@@ -3357,6 +3355,14 @@
          */
         public static final int SIZE_LARGE = 4;
 
+        /**
+         * Size value for use with {@link #setCustomSizePreset} to show this notification
+         * full screen.
+         * <p>This value is only applicable for custom display notifications created using
+         * {@link #setDisplayIntent}.
+         */
+        public static final int SIZE_FULL_SCREEN = 5;
+
         /** Notification extra which contains wearable extensions */
         private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
 
@@ -3553,7 +3559,27 @@
 
         /**
          * Set an intent to launch inside of an activity view when displaying
-         * this notification. This {@link PendingIntent} should be for an activity.
+         * this notification. The {@link PendingIntent} provided should be for an activity.
+         *
+         * <pre class="prettyprint">
+         * Intent displayIntent = new Intent(context, MyDisplayActivity.class);
+         * PendingIntent displayPendingIntent = PendingIntent.getActivity(context,
+         *         0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+         * Notification notif = new Notification.Builder(context)
+         *         .extend(new Notification.WearableExtender()
+         *                 .setDisplayIntent(displayPendingIntent)
+         *                 .setCustomSizePreset(Notification.WearableExtender.SIZE_MEDIUM))
+         *         .build();</pre>
+         *
+         * <p>The activity to launch needs to allow embedding, must be exported, and
+         * should have an empty task affinity.
+         *
+         * <p>Example AndroidManifest.xml entry:
+         * <pre class="prettyprint">
+         * &lt;activity android:name=&quot;com.example.MyDisplayActivity&quot;
+         *     android:exported=&quot;true&quot;
+         *     android:allowEmbedded=&quot;true&quot;
+         *     android:taskAffinity=&quot;&quot; /&gt;</pre>
          *
          * @param intent the {@link PendingIntent} for an activity
          * @return this object for method chaining
@@ -3687,12 +3713,17 @@
 
         /**
          * Set an action from this notification's actions to be clickable with the content of
-         * this notification page. This action will no longer display separately from the
-         * notification content. This action's icon will display with optional subtext provided
-         * by the action's title.
-         * @param actionIndex The index of the action to hoist on the current notification page.
-         *                    If wearable actions are present, this index will apply to that list,
-         *                    otherwise it will apply to the main notification's actions list.
+         * this notification. This action will no longer display separately from the
+         * notification's content.
+         *
+         * <p>For notifications with multiple pages, child pages can also have content action's
+         * set, although the list of available actions comes from the main notification and not
+         * from the child page's notification.
+         *
+         * @param actionIndex The index of the action to hoist onto the current notification page.
+         *                    If wearable actions were added to the main notification, this index
+         *                    will apply to that list, otherwise it will apply to the regular
+         *                    actions list.
          */
         public WearableExtender setContentAction(int actionIndex) {
             mContentActionIndex = actionIndex;
@@ -3700,14 +3731,16 @@
         }
 
         /**
-         * Get the action index of an action from this notification to show as clickable with
-         * the content of this notification page. When the user clicks this notification page,
-         * this action will trigger. This action will no longer display separately from the
-         * notification content. The action's icon will display with optional subtext provided
-         * by the action's title.
+         * Get the action index from this notification's actions to be clickable with the
+         * content of this notification. This action will no longer display separately
+         * from the notification's content.
          *
-         * <p>If wearable specific actions are present, this index will apply to that list,
-         * otherwise it will apply to the main notification's actions list.
+         * <p>For notifications with multiple pages, child pages can also have content action's
+         * set, although the list of available actions comes from the main notification and not
+         * from the child page's notification.
+         *
+         * <p>If wearable specific actions were added to the main notification, this index will
+         * apply to that list, otherwise it will apply to the regular actions list.
          */
         public int getContentAction() {
             return mContentActionIndex;
diff --git a/core/java/android/app/TaskManagerImpl.java b/core/java/android/app/TaskManagerImpl.java
new file mode 100644
index 0000000..f42839e
--- /dev/null
+++ b/core/java/android/app/TaskManagerImpl.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+// in android.app so ContextImpl has package access
+package android.app;
+
+import android.app.task.ITaskManager;
+import android.app.task.Task;
+import android.app.task.TaskManager;
+
+import java.util.List;
+
+
+/**
+ * Concrete implementation of the TaskManager interface
+ * @hide 
+ */
+public class TaskManagerImpl extends TaskManager {
+    ITaskManager mBinder;
+
+    /* package */ TaskManagerImpl(ITaskManager binder) {
+        mBinder = binder;
+    }
+
+    @Override
+    public int schedule(Task task) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public void cancel(int taskId) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void cancelAll() {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public List<Task> getAllPendingTasks() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 77b1acf..6b486c4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -176,15 +176,16 @@
     public static final String ACTION_SET_NEW_PASSWORD
             = "android.app.action.SET_NEW_PASSWORD";
     /**
-     * Flag for {@link #addForwardingIntentFilter}: the intents will forwarded to the primary user.
+     * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from a
+     * managed profile to its parent.
      */
-    public static int FLAG_TO_PRIMARY_USER = 0x0001;
+    public static int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
 
     /**
-     * Flag for {@link #addForwardingIntentFilter}: the intents will be forwarded to the managed
-     * profile.
+     * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from the
+     * parent to its managed profile.
      */
-    public static int FLAG_TO_MANAGED_PROFILE = 0x0002;
+    public static int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
 
     /**
      * Return true if the given administrator component is currently
@@ -1951,17 +1952,16 @@
     }
 
     /**
-     * Called by a profile owner to forward intents sent from the managed profile to the owner, or
-     * from the owner to the managed profile.
-     * If an intent matches this intent filter, then activities belonging to the other user can
-     * respond to this intent.
+     * Called by the profile owner so that some intents sent in the managed profile can also be
+     * resolved in the parent, or vice versa.
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param filter if an intent matches this IntentFilter, then it can be forwarded.
+     * @param filter The {@link IntentFilter} the intent has to match to be also resolved in the
+     * other profile
      */
-    public void addForwardingIntentFilter(ComponentName admin, IntentFilter filter, int flags) {
+    public void addCrossProfileIntentFilter(ComponentName admin, IntentFilter filter, int flags) {
         if (mService != null) {
             try {
-                mService.addForwardingIntentFilter(admin, filter, flags);
+                mService.addCrossProfileIntentFilter(admin, filter, flags);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1969,14 +1969,14 @@
     }
 
     /**
-     * Called by a profile owner to remove the forwarding intent filters from the current user
-     * and from the owner.
+     * Called by a profile owner to remove the cross-profile intent filters from the managed profile
+     * and from the parent.
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      */
-    public void clearForwardingIntentFilters(ComponentName admin) {
+    public void clearCrossProfileIntentFilters(ComponentName admin) {
         if (mService != null) {
             try {
-                mService.clearForwardingIntentFilters(admin);
+                mService.clearCrossProfileIntentFilters(admin);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 3c08c14..cc6d715 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -122,8 +122,8 @@
     Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
 
     void setUserRestriction(in ComponentName who, in String key, boolean enable);
-    void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
-    void clearForwardingIntentFilters(in ComponentName admin);
+    void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
+    void clearCrossProfileIntentFilters(in ComponentName admin);
 
     boolean setApplicationBlocked(in ComponentName admin, in String packageName, boolean blocked);
     int setApplicationsBlocked(in ComponentName admin, in Intent intent, boolean blocked);
diff --git a/core/java/android/app/task/ITaskManager.aidl b/core/java/android/app/task/ITaskManager.aidl
new file mode 100644
index 0000000..b56c78a
--- /dev/null
+++ b/core/java/android/app/task/ITaskManager.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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.app.task;
+
+import android.app.task.Task;
+
+ /**
+  * IPC interface that supports the app-facing {@link #TaskManager} api.
+  * {@hide}
+  */
+interface ITaskManager {
+    int schedule(in Task task);
+    void cancel(int taskId);
+    void cancelAll();
+    List<Task> getAllPendingTasks();
+}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/task/Task.aidl
new file mode 100644
index 0000000..1f25439
--- /dev/null
+++ b/core/java/android/app/task/Task.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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.app.task;
+
+parcelable Task;
+ 
\ No newline at end of file
diff --git a/core/java/android/app/task/Task.java b/core/java/android/app/task/Task.java
new file mode 100644
index 0000000..ca4aeb2
--- /dev/null
+++ b/core/java/android/app/task/Task.java
@@ -0,0 +1,421 @@
+/*
+ * 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.app.task;
+
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container of data passed to the {@link android.app.task.TaskManager} fully encapsulating the
+ * parameters required to schedule work against the calling application. These are constructed
+ * using the {@link Task.Builder}.
+ */
+public class Task implements Parcelable {
+    public interface NetworkType {
+        /** Default. */
+        public final int NONE = 0;
+        /** This task requires network connectivity. */
+        public final int ANY = 1;
+        /** This task requires network connectivity that is unmetered. */
+        public final int UNMETERED = 2;
+    }
+
+    /**
+     * Linear: retry_time(failure_time, t) = failure_time + initial_retry_delay * t, t >= 1
+     * Expon: retry_time(failure_time, t) = failure_time + initial_retry_delay ^ t, t >= 1
+     */
+    public interface BackoffPolicy {
+        public final int LINEAR = 0;
+        public final int EXPONENTIAL = 1;
+    }
+
+    private final int taskId;
+    // TODO: Change this to use PersistableBundle when that lands in master.
+    private final Bundle extras;
+    private final ComponentName service;
+    private final boolean requireCharging;
+    private final boolean requireDeviceIdle;
+    private final boolean hasEarlyConstraint;
+    private final boolean hasLateConstraint;
+    private final int networkCapabilities;
+    private final long minLatencyMillis;
+    private final long maxExecutionDelayMillis;
+    private final boolean isPeriodic;
+    private final long intervalMillis;
+    private final long initialBackoffMillis;
+    private final int backoffPolicy;
+
+    /**
+     * Unique task id associated with this class. This is assigned to your task by the scheduler.
+     */
+    public int getId() {
+        return taskId;
+    }
+
+    /**
+     * Bundle of extras which are returned to your application at execution time.
+     */
+    public Bundle getExtras() {
+        return extras;
+    }
+
+    /**
+     * Name of the service endpoint that will be called back into by the TaskManager.
+     */
+    public ComponentName getService() {
+        return service;
+    }
+
+    /**
+     * Whether this task needs the device to be plugged in.
+     */
+    public boolean isRequireCharging() {
+        return requireCharging;
+    }
+
+    /**
+     * Whether this task needs the device to be in an Idle maintenance window.
+     */
+    public boolean isRequireDeviceIdle() {
+        return requireDeviceIdle;
+    }
+
+    /**
+     * See {@link android.app.task.Task.NetworkType} for a description of this value.
+     */
+    public int getNetworkCapabilities() {
+        return networkCapabilities;
+    }
+
+    /**
+     * Set for a task that does not recur periodically, to specify a delay after which the task
+     * will be eligible for execution. This value is not set if the task recurs periodically.
+     */
+    public long getMinLatencyMillis() {
+        return minLatencyMillis;
+    }
+
+    /**
+     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
+     * periodically.
+     */
+    public long getMaxExecutionDelayMillis() {
+        return maxExecutionDelayMillis;
+    }
+
+    /**
+     * Track whether this task will repeat with a given period.
+     */
+    public boolean isPeriodic() {
+        return isPeriodic;
+    }
+
+    /**
+     * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
+     * task does not recur periodically.
+     */
+    public long getIntervalMillis() {
+        return intervalMillis;
+    }
+
+    /**
+     * The amount of time the TaskManager will wait before rescheduling a failed task. This value
+     * will be increased depending on the backoff policy specified at task creation time. Defaults
+     * to 5 seconds.
+     */
+    public long getInitialBackoffMillis() {
+        return initialBackoffMillis;
+    }
+
+    /**
+     * See {@link android.app.task.Task.BackoffPolicy} for an explanation of the values this field
+     * can take. This defaults to exponential.
+     */
+    public int getBackoffPolicy() {
+        return backoffPolicy;
+    }
+
+    /**
+     * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
+     * function was called at all.
+     * @hide
+     */
+    public boolean hasEarlyConstraint() {
+        return hasEarlyConstraint;
+    }
+
+    /**
+     * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
+     * function was called at all.
+     * @hide
+     */
+    public boolean hasLateConstraint() {
+        return hasLateConstraint;
+    }
+
+    private Task(Parcel in) {
+        taskId = in.readInt();
+        extras = in.readBundle();
+        service = ComponentName.readFromParcel(in);
+        requireCharging = in.readInt() == 1;
+        requireDeviceIdle = in.readInt() == 1;
+        networkCapabilities = in.readInt();
+        minLatencyMillis = in.readLong();
+        maxExecutionDelayMillis = in.readLong();
+        isPeriodic = in.readInt() == 1;
+        intervalMillis = in.readLong();
+        initialBackoffMillis = in.readLong();
+        backoffPolicy = in.readInt();
+        hasEarlyConstraint = in.readInt() == 1;
+        hasLateConstraint = in.readInt() == 1;
+    }
+
+    private Task(Task.Builder b) {
+        taskId = b.mTaskId;
+        extras = new Bundle(b.mExtras);
+        service = b.mTaskService;
+        requireCharging = b.mRequiresCharging;
+        requireDeviceIdle = b.mRequiresDeviceIdle;
+        networkCapabilities = b.mNetworkCapabilities;
+        minLatencyMillis = b.mMinLatencyMillis;
+        maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
+        isPeriodic = b.mIsPeriodic;
+        intervalMillis = b.mIntervalMillis;
+        initialBackoffMillis = b.mInitialBackoffMillis;
+        backoffPolicy = b.mBackoffPolicy;
+        hasEarlyConstraint = b.mHasEarlyConstraint;
+        hasLateConstraint = b.mHasLateConstraint;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(taskId);
+        out.writeBundle(extras);
+        ComponentName.writeToParcel(service, out);
+        out.writeInt(requireCharging ? 1 : 0);
+        out.writeInt(requireDeviceIdle ? 1 : 0);
+        out.writeInt(networkCapabilities);
+        out.writeLong(minLatencyMillis);
+        out.writeLong(maxExecutionDelayMillis);
+        out.writeInt(isPeriodic ? 1 : 0);
+        out.writeLong(intervalMillis);
+        out.writeLong(initialBackoffMillis);
+        out.writeInt(backoffPolicy);
+        out.writeInt(hasEarlyConstraint ? 1 : 0);
+        out.writeInt(hasLateConstraint ? 1 : 0);
+    }
+
+    public static final Creator<Task> CREATOR = new Creator<Task>() {
+        @Override
+        public Task createFromParcel(Parcel in) {
+            return new Task(in);
+        }
+
+        @Override
+        public Task[] newArray(int size) {
+            return new Task[size];
+        }
+    };
+
+    /**
+     * Builder class for constructing {@link Task} objects.
+     */
+    public static final class Builder {
+        private int mTaskId;
+        private Bundle mExtras;
+        private ComponentName mTaskService;
+        // Requirements.
+        private boolean mRequiresCharging;
+        private boolean mRequiresDeviceIdle;
+        private int mNetworkCapabilities;
+        // One-off parameters.
+        private long mMinLatencyMillis;
+        private long mMaxExecutionDelayMillis;
+        // Periodic parameters.
+        private boolean mIsPeriodic;
+        private boolean mHasEarlyConstraint;
+        private boolean mHasLateConstraint;
+        private long mIntervalMillis;
+        // Back-off parameters.
+        private long mInitialBackoffMillis = 5000L;
+        private int mBackoffPolicy = BackoffPolicy.EXPONENTIAL;
+        /** Easy way to track whether the client has tried to set a back-off policy. */
+        private boolean mBackoffPolicySet = false;
+
+        /**
+         * @param taskId Application-provided id for this task. Subsequent calls to cancel, or
+         *               tasks created with the same taskId, will update the pre-existing task with
+         *               the same id.
+         * @param taskService The endpoint that you implement that will receive the callback from the
+         *            TaskManager.
+         */
+        public Builder(int taskId, ComponentName taskService) {
+            mTaskService = taskService;
+            mTaskId = taskId;
+        }
+
+        /**
+         * Set optional extras. This is persisted, so we only allow primitive types.
+         * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+         */
+        public Builder setExtras(Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Set some description of the kind of network capabilities you would like to have. This
+         * will be a parameter defined in {@link android.app.task.Task.NetworkType}.
+         * Not calling this function means the network is not necessary.
+         * Bear in mind that calling this function defines network as a strict requirement for your
+         * task if the network requested is not available your task will never run. See
+         * {@link #setOverrideDeadline(long)} to change this behaviour.
+         */
+        public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
+            mNetworkCapabilities = networkCapabilities;
+            return this;
+        }
+
+        /*
+         * Specify that to run this task, the device needs to be plugged in. This defaults to
+         * false.
+         * @param requireCharging Whether or not the device is plugged in.
+         */
+        public Builder setRequiresCharging(boolean requiresCharging) {
+            mRequiresCharging = requiresCharging;
+            return this;
+        }
+
+        /**
+         * Specify that to run, the task needs the device to be in idle mode. This defaults to
+         * false.
+         * <p>Idle mode is a loose definition provided by the system, which means that the device
+         * is not in use, and has not been in use for some time. As such, it is a good time to
+         * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
+         * to your application, and surfaced to the user in battery stats.</p>
+         * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
+         *                           window.
+         */
+        public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
+            mRequiresDeviceIdle = requiresDeviceIdle;
+            return this;
+        }
+
+        /**
+         * Specify that this task should recur with the provided interval, not more than once per
+         * period. You have no control over when within this interval this task will be executed,
+         * only the guarantee that it will be executed at most once within this interval.
+         * A periodic task will be repeated until the phone is turned off, however it will only be
+         * persisted beyond boot if the client app has declared the
+         * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
+         * periodic tasks without this permission, they simply will cease to exist after the phone
+         * restarts.
+         * Setting this function on the builder with {@link #setMinimumLatency(long)} or
+         * {@link #setOverrideDeadline(long)} will result in an error.
+         * @param intervalMillis Millisecond interval for which this task will repeat.
+         */
+        public Builder setPeriodic(long intervalMillis) {
+            mIsPeriodic = true;
+            mIntervalMillis = intervalMillis;
+            mHasEarlyConstraint = mHasLateConstraint = true;
+            return this;
+        }
+
+        /**
+         * Specify that this task should be delayed by the provided amount of time.
+         * Because it doesn't make sense setting this property on a periodic task, doing so will
+         * throw an {@link java.lang.IllegalArgumentException} when
+         * {@link android.app.task.Task.Builder#build()} is called.
+         * @param minLatencyMillis Milliseconds before which this task will not be considered for
+         *                         execution.
+         */
+        public Builder setMinimumLatency(long minLatencyMillis) {
+            mMinLatencyMillis = minLatencyMillis;
+            mHasEarlyConstraint = true;
+            return this;
+        }
+
+        /**
+         * Set deadline which is the maximum scheduling latency. The task will be run by this
+         * deadline even if other requirements are not met. Because it doesn't make sense setting
+         * this property on a periodic task, doing so will throw an
+         * {@link java.lang.IllegalArgumentException} when
+         * {@link android.app.task.Task.Builder#build()} is called.
+         */
+        public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
+            mMaxExecutionDelayMillis = maxExecutionDelayMillis;
+            mHasLateConstraint = true;
+            return this;
+        }
+
+        /**
+         * Set up the back-off/retry policy.
+         * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
+         * 1hr.
+         * Note that trying to set a backoff criteria for a task with
+         * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
+         * This is because back-off typically does not make sense for these types of tasks. See
+         * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+         * for more description of the return value for the case of a task executing while in idle
+         * mode.
+         * @param initialBackoffMillis Millisecond time interval to wait initially when task has
+         *                             failed.
+         * @param backoffPolicy is one of {@link BackoffPolicy}
+         */
+        public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
+            mBackoffPolicySet = true;
+            mInitialBackoffMillis = initialBackoffMillis;
+            mBackoffPolicy = backoffPolicy;
+            return this;
+        }
+
+        /**
+         * @return The task object to hand to the TaskManager. This object is immutable.
+         */
+        public Task build() {
+            if (mExtras == null) {
+                mExtras = Bundle.EMPTY;
+            }
+            if (mTaskId < 0) {
+                throw new IllegalArgumentException("Task id must be greater than 0.");
+            }
+            // Check that a deadline was not set on a periodic task.
+            if (mIsPeriodic && mHasLateConstraint) {
+                throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
+                        "periodic task.");
+            }
+            if (mIsPeriodic && mHasEarlyConstraint) {
+                throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
+                        "periodic task");
+            }
+            if (mBackoffPolicySet && mRequiresDeviceIdle) {
+                throw new IllegalArgumentException("An idle mode task will not respect any" +
+                        " back-off policy, so calling setBackoffCriteria with" +
+                        " setRequiresDeviceIdle is an error.");
+            }
+            return new Task(this);
+        }
+    }
+
+}
diff --git a/core/java/android/app/task/TaskManager.java b/core/java/android/app/task/TaskManager.java
new file mode 100644
index 0000000..00f57da
--- /dev/null
+++ b/core/java/android/app/task/TaskManager.java
@@ -0,0 +1,72 @@
+/*
+ * 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.app.task;
+
+import java.util.List;
+
+import android.content.Context;
+
+/**
+ * Class for scheduling various types of tasks with the scheduling framework on the device.
+ *
+ * <p>You do not
+ * instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.TASK_SERVICE)}.
+ */
+public abstract class TaskManager {
+    /*
+     * Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
+     * if the run-time for your task is too short, or perhaps the system can't resolve the
+     * requisite {@link TaskService} in your package.
+     */
+    public static final int RESULT_FAILURE = 0;
+    /**
+     * Returned from {@link #schedule(Task)} if this application has made too many requests for
+     * work over too short a time.
+     */
+    // TODO: Determine if this is necessary.
+    public static final int RESULT_SUCCESS = 1;
+
+    /**
+     * @param task The task you wish scheduled. See
+     * {@link android.app.task.Task.Builder Task.Builder} for more detail on the sorts of tasks
+     * you can schedule.
+     * @return If >0, this int returns the taskId of the successfully scheduled task.
+     * Otherwise you have to compare the return value to the error codes defined in this class.
+     */
+    public abstract int schedule(Task task);
+
+    /**
+     * Cancel a task that is pending in the TaskManager.
+     * @param taskId unique identifier for this task. Obtain this value from the tasks returned by
+     * {@link #getAllPendingTasks()}.
+     * @return
+     */
+    public abstract void cancel(int taskId);
+
+    /**
+     * Cancel all tasks that have been registered with the TaskManager by this package.
+     */
+    public abstract void cancelAll();
+
+    /**
+     * @return a list of all the tasks registered by this package that have not yet been executed.
+     */
+    public abstract List<Task> getAllPendingTasks();
+
+}
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
index 0351082..dacb3480 100644
--- a/core/java/android/app/task/TaskParams.java
+++ b/core/java/android/app/task/TaskParams.java
@@ -47,7 +47,7 @@
 
     /**
      * @return The extras you passed in when constructing this task with
-     * {@link android.content.Task.Builder#setExtras(android.os.Bundle)}. This will
+     * {@link android.app.task.Task.Builder#setExtras(android.os.Bundle)}. This will
      * never be null. If you did not set any extras this will be an empty bundle.
      */
     public Bundle getExtras() {
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
index ab1a565..8ce4484 100644
--- a/core/java/android/app/task/TaskService.java
+++ b/core/java/android/app/task/TaskService.java
@@ -28,7 +28,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 /**
- * <p>Entry point for the callback from the {@link android.content.TaskManager}.</p>
+ * <p>Entry point for the callback from the {@link android.app.task.TaskManager}.</p>
  * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
  * are responsible for overriding {@link TaskService#onStartTask(TaskParams)}, which is where
  * you will implement your task logic.</p>
@@ -215,9 +215,9 @@
      *
      * <p>This will happen if the requirements specified at schedule time are no longer met. For
      * example you may have requested WiFi with
-     * {@link android.content.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+     * {@link android.app.task.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
      * task was executing the user toggled WiFi. Another example is if you had specified
-     * {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+     * {@link android.app.task.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
      * idle maintenance window. You are solely responsible for the behaviour of your application
      * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
      * immediate repercussion is that the system will cease holding a wakelock for you.</p>
@@ -237,7 +237,7 @@
      *     You can specify post-execution behaviour to the scheduler here with
      *     <code>needsReschedule </code>. This will apply a back-off timer to your task based on
      *     the default, or what was set with
-     *     {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The original
+     *     {@link android.app.task.Task.Builder#setBackoffCriteria(long, int)}. The original
      *     requirements are always honoured even for a backed-off task. Note that a task running in
      *     idle mode will not be backed-off. Instead what will happen is the task will be re-added
      *     to the queue and re-executed within a future idle maintenance window.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6ae006c..b0673b5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2023,6 +2023,7 @@
             PRINT_SERVICE,
             MEDIA_SESSION_SERVICE,
             BATTERY_SERVICE,
+            TASK_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2079,6 +2080,8 @@
      * <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
      * <dt> {@link #BATTERY_SERVICE} ("batterymanager")
      * <dd> A {@link android.os.BatteryManager} for managing battery state
+     * <dt> {@link #TASK_SERVICE} ("taskmanager")
+     * <dd>  A {@link android.app.task.TaskManager} for managing scheduled tasks
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -2134,6 +2137,8 @@
      * @see android.app.DownloadManager
      * @see #BATTERY_SERVICE
      * @see android.os.BatteryManager
+     * @see #TASK_SERVICE
+     * @see android.app.task.TaskManager
      */
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
@@ -2728,6 +2733,15 @@
     public static final String USAGE_STATS_SERVICE = "usagestats";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.app.task.TaskManager} instance for managing occasional
+     * background tasks.
+     * @see #getSystemService
+     * @see android.app.task.TaskManager
+     */
+    public static final String TASK_SERVICE = "task";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 076f657..bd07470 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -45,6 +45,7 @@
 import android.util.Log;
 
 import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.io.Serializable;
@@ -604,6 +605,15 @@
  * of all possible flags.
  */
 public class Intent implements Parcelable, Cloneable {
+    private static final String ATTR_ACTION = "action";
+    private static final String TAG_CATEGORIES = "categories";
+    private static final String ATTR_CATEGORY = "category";
+    private static final String TAG_EXTRA = "extra";
+    private static final String ATTR_TYPE = "type";
+    private static final String ATTR_COMPONENT = "component";
+    private static final String ATTR_DATA = "data";
+    private static final String ATTR_FLAGS = "flags";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent activity actions (see action variable).
@@ -3729,32 +3739,27 @@
      */
     public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000;
     /**
-     * This flag is used to break out "documents" into separate tasks that can
-     * be reached via the Recents mechanism. Such a document is any kind of
-     * item for which an application may want to maintain multiple simultaneous
-     * instances. Examples might be text files, web pages, spreadsheets, or
-     * emails. Each such document will be in a separate task in the Recents list.
+     * This flag is used to open a document into a new task rooted at the activity launched
+     * by this Intent. Through the use of this flag, or its equivalent attribute,
+     * {@link android.R.attr#documentLaunchMode} multiple instances of the same activity
+     * containing different douments will appear in the recent tasks list.
      *
-     * <p>When set, the activity specified by this Intent will launch into a
-     * separate task rooted at that activity. The activity launched must be
-     * defined with {@link android.R.attr#launchMode} <code>standard</code>
-     * or <code>singleTop</code>.
+     * <p>The use of the activity attribute form of this,
+     * {@link android.R.attr#documentLaunchMode}, is
+     * preferred over the Intent flag described here. The attribute form allows the
+     * Activity to specify multiple document behavior for all launchers of the Activity
+     * whereas using this flag requires each Intent that launches the Activity to specify it.
      *
-     * <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without
-     * {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will
-     * search for an existing task with a matching target activity and Intent
-     * data URI and relaunch that task, first finishing all activities down to
-     * the root activity and then calling the root activity's
-     * {@link android.app.Activity#onNewIntent(Intent)} method. If no existing
-     * task's root activity matches the Intent's data URI then a new task will
-     * be launched with the target activity as root.
+     * <p>FLAG_ACTIVITY_NEW_DOCUMENT may be used in conjunction with {@link
+     * #FLAG_ACTIVITY_MULTIPLE_TASK}. When used alone it is the
+     * equivalent of the Activity manifest specifying {@link
+     * android.R.attr#documentLaunchMode}="intoExisting". When used with
+     * FLAG_ACTIVITY_MULTIPLE_TASK it is the equivalent of the Activity manifest specifying
+     * {@link android.R.attr#documentLaunchMode}="always".
      *
-     * <p>When paired with {@link #FLAG_ACTIVITY_MULTIPLE_TASK} this will
-     * always create a new task. Thus the same document may be made to appear
-     * more than one time in Recents.
+     * Refer to {@link android.R.attr#documentLaunchMode} for more information.
      *
-     * <p>This is equivalent to the attribute {@link android.R.attr#documentLaunchMode}.
-     *
+     * @see android.R.attr#documentLaunchMode
      * @see #FLAG_ACTIVITY_MULTIPLE_TASK
      */
     public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
@@ -7347,7 +7352,7 @@
             }
 
             String nodeName = parser.getName();
-            if (nodeName.equals("category")) {
+            if (nodeName.equals(TAG_CATEGORIES)) {
                 sa = resources.obtainAttributes(attrs,
                         com.android.internal.R.styleable.IntentCategory);
                 String cat = sa.getString(com.android.internal.R.styleable.IntentCategory_name);
@@ -7358,11 +7363,11 @@
                 }
                 XmlUtils.skipCurrentTag(parser);
 
-            } else if (nodeName.equals("extra")) {
+            } else if (nodeName.equals(TAG_EXTRA)) {
                 if (intent.mExtras == null) {
                     intent.mExtras = new Bundle();
                 }
-                resources.parseBundleExtra("extra", attrs, intent.mExtras);
+                resources.parseBundleExtra(TAG_EXTRA, attrs, intent.mExtras);
                 XmlUtils.skipCurrentTag(parser);
 
             } else {
@@ -7373,6 +7378,76 @@
         return intent;
     }
 
+    /** @hide */
+    public void saveToXml(XmlSerializer out) throws IOException {
+        if (mAction != null) {
+            out.attribute(null, ATTR_ACTION, mAction);
+        }
+        if (mData != null) {
+            out.attribute(null, ATTR_DATA, mData.toString());
+        }
+        if (mType != null) {
+            out.attribute(null, ATTR_TYPE, mType);
+        }
+        if (mComponent != null) {
+            out.attribute(null, ATTR_COMPONENT, mComponent.flattenToShortString());
+        }
+        out.attribute(null, ATTR_FLAGS, Integer.toHexString(getFlags()));
+
+        if (mCategories != null) {
+            out.startTag(null, TAG_CATEGORIES);
+            for (int categoryNdx = mCategories.size() - 1; categoryNdx >= 0; --categoryNdx) {
+                out.attribute(null, ATTR_CATEGORY, mCategories.valueAt(categoryNdx));
+            }
+        }
+    }
+
+    /** @hide */
+    public static Intent restoreFromXml(XmlPullParser in) throws IOException,
+            XmlPullParserException {
+        Intent intent = new Intent();
+        final int outerDepth = in.getDepth();
+
+        int attrCount = in.getAttributeCount();
+        for (int attrNdx = attrCount - 1; attrNdx >= 0; --attrNdx) {
+            final String attrName = in.getAttributeName(attrNdx);
+            final String attrValue = in.getAttributeValue(attrNdx);
+            if (ATTR_ACTION.equals(attrName)) {
+                intent.setAction(attrValue);
+            } else if (ATTR_DATA.equals(attrName)) {
+                intent.setData(Uri.parse(attrValue));
+            } else if (ATTR_TYPE.equals(attrName)) {
+                intent.setType(attrValue);
+            } else if (ATTR_COMPONENT.equals(attrName)) {
+                intent.setComponent(ComponentName.unflattenFromString(attrValue));
+            } else if (ATTR_FLAGS.equals(attrName)) {
+                intent.setFlags(Integer.valueOf(attrValue, 16));
+            } else {
+                Log.e("Intent", "restoreFromXml: unknown attribute=" + attrName);
+            }
+        }
+
+        int event;
+        String name;
+        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
+                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
+            if (event == XmlPullParser.START_TAG) {
+                name = in.getName();
+                if (TAG_CATEGORIES.equals(name)) {
+                    attrCount = in.getAttributeCount();
+                    for (int attrNdx = attrCount - 1; attrNdx >= 0; --attrNdx) {
+                        intent.addCategory(in.getAttributeValue(attrNdx));
+                    }
+                } else {
+                    Log.w("Intent", "restoreFromXml: unknown name=" + name);
+                    XmlUtils.skipCurrentTag(in);
+                }
+            }
+        }
+
+        return intent;
+    }
+
     /**
      * Normalize a MIME data type.
      *
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 6b4404d..46c9234 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -355,7 +355,14 @@
     
     /**
      * Registers a callback to be invoked when a change happens to a preference.
-     * 
+     *
+     * <p class="caution"><strong>Caution:</strong> The preference manager does
+     * not currently store a strong reference to the listener. You must store a
+     * strong reference to the listener, or it will be susceptible to garbage
+     * collection. We recommend you keep a reference to the listener in the
+     * instance data of an object that will exist as long as you need the
+     * listener.</p>
+     *
      * @param listener The callback that will run.
      * @see #unregisterOnSharedPreferenceChangeListener
      */
diff --git a/core/java/android/content/Task.java b/core/java/android/content/Task.java
deleted file mode 100644
index 407880f..0000000
--- a/core/java/android/content/Task.java
+++ /dev/null
@@ -1,400 +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.content;
-
-import android.app.task.TaskService;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Container of data passed to the {@link android.content.TaskManager} fully encapsulating the
- * parameters required to schedule work against the calling application. These are constructed
- * using the {@link Task.Builder}.
- */
-public class Task implements Parcelable {
-
-    public interface NetworkType {
-        public final int ANY = 0;
-        public final int UNMETERED = 1;
-    }
-
-    /**
-     * Linear: retry_time(failure_time, t) = failure_time + initial_retry_delay * t, t >= 1
-     * Expon: retry_time(failure_time, t) = failure_time + initial_retry_delay ^ t, t >= 1
-     */
-    public interface BackoffPolicy {
-        public final int LINEAR = 0;
-        public final int EXPONENTIAL = 1;
-    }
-
-    private final int taskId;
-    // TODO: Change this to use PersistableBundle when that lands in master.
-    private final Bundle extras;
-    private final ComponentName service;
-    private final boolean requireCharging;
-    private final boolean requireDeviceIdle;
-    private final int networkCapabilities;
-    private final long minLatencyMillis;
-    private final long maxExecutionDelayMillis;
-    private final boolean isPeriodic;
-    private final long intervalMillis;
-    private final long initialBackoffMillis;
-    private final int backoffPolicy;
-
-    /**
-     * Unique task id associated with this class. This is assigned to your task by the scheduler.
-     */
-    public int getTaskId() {
-        return taskId;
-    }
-
-    /**
-     * Bundle of extras which are returned to your application at execution time.
-     */
-    public Bundle getExtras() {
-        return extras;
-    }
-
-    /**
-     * Name of the service endpoint that will be called back into by the TaskManager.
-     */
-    public ComponentName getService() {
-        return service;
-    }
-
-    /**
-     * Whether this task needs the device to be plugged in.
-     */
-    public boolean isRequireCharging() {
-        return requireCharging;
-    }
-
-    /**
-     * Whether this task needs the device to be in an Idle maintenance window.
-     */
-    public boolean isRequireDeviceIdle() {
-        return requireDeviceIdle;
-    }
-
-    /**
-     * See {@link android.content.Task.NetworkType} for a description of this value.
-     */
-    public int getNetworkCapabilities() {
-        return networkCapabilities;
-    }
-
-    /**
-     * Set for a task that does not recur periodically, to specify a delay after which the task
-     * will be eligible for execution. This value is not set if the task recurs periodically.
-     */
-    public long getMinLatencyMillis() {
-        return minLatencyMillis;
-    }
-
-    /**
-     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
-     * periodically.
-     */
-    public long getMaxExecutionDelayMillis() {
-        return maxExecutionDelayMillis;
-    }
-
-    /**
-     * Track whether this task will repeat with a given period.
-     */
-    public boolean isPeriodic() {
-        return isPeriodic;
-    }
-
-    /**
-     * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
-     * task does not recur periodically.
-     */
-    public long getIntervalMillis() {
-        return intervalMillis;
-    }
-
-    /**
-     * The amount of time the TaskManager will wait before rescheduling a failed task. This value
-     * will be increased depending on the backoff policy specified at task creation time. Defaults
-     * to 5 seconds.
-     */
-    public long getInitialBackoffMillis() {
-        return initialBackoffMillis;
-    }
-
-    /**
-     * See {@link android.content.Task.BackoffPolicy} for an explanation of the values this field
-     * can take. This defaults to exponential.
-     */
-    public int getBackoffPolicy() {
-        return backoffPolicy;
-    }
-
-    private Task(Parcel in) {
-        taskId = in.readInt();
-        extras = in.readBundle();
-        service = ComponentName.readFromParcel(in);
-        requireCharging = in.readInt() == 1;
-        requireDeviceIdle = in.readInt() == 1;
-        networkCapabilities = in.readInt();
-        minLatencyMillis = in.readLong();
-        maxExecutionDelayMillis = in.readLong();
-        isPeriodic = in.readInt() == 1;
-        intervalMillis = in.readLong();
-        initialBackoffMillis = in.readLong();
-        backoffPolicy = in.readInt();
-    }
-
-    private Task(Task.Builder b) {
-        taskId = b.mTaskId;
-        extras = new Bundle(b.mExtras);
-        service = b.mTaskService;
-        requireCharging = b.mRequiresCharging;
-        requireDeviceIdle = b.mRequiresDeviceIdle;
-        networkCapabilities = b.mNetworkCapabilities;
-        minLatencyMillis = b.mMinLatencyMillis;
-        maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
-        isPeriodic = b.mIsPeriodic;
-        intervalMillis = b.mIntervalMillis;
-        initialBackoffMillis = b.mInitialBackoffMillis;
-        backoffPolicy = b.mBackoffPolicy;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(taskId);
-        out.writeBundle(extras);
-        ComponentName.writeToParcel(service, out);
-        out.writeInt(requireCharging ? 1 : 0);
-        out.writeInt(requireDeviceIdle ? 1 : 0);
-        out.writeInt(networkCapabilities);
-        out.writeLong(minLatencyMillis);
-        out.writeLong(maxExecutionDelayMillis);
-        out.writeInt(isPeriodic ? 1 : 0);
-        out.writeLong(intervalMillis);
-        out.writeLong(initialBackoffMillis);
-        out.writeInt(backoffPolicy);
-    }
-
-    public static final Creator<Task> CREATOR = new Creator<Task>() {
-        @Override
-        public Task createFromParcel(Parcel in) {
-            return new Task(in);
-        }
-
-        @Override
-        public Task[] newArray(int size) {
-            return new Task[size];
-        }
-    };
-
-    /**
-     * Builder class for constructing {@link Task} objects.
-     */
-    public final class Builder {
-        private int mTaskId;
-        private Bundle mExtras;
-        private ComponentName mTaskService;
-        // Requirements.
-        private boolean mRequiresCharging;
-        private boolean mRequiresDeviceIdle;
-        private int mNetworkCapabilities;
-        // One-off parameters.
-        private long mMinLatencyMillis;
-        private long mMaxExecutionDelayMillis;
-        // Periodic parameters.
-        private boolean mIsPeriodic;
-        private long mIntervalMillis;
-        // Back-off parameters.
-        private long mInitialBackoffMillis = 5000L;
-        private int mBackoffPolicy = BackoffPolicy.EXPONENTIAL;
-        /** Easy way to track whether the client has tried to set a back-off policy. */
-        private boolean mBackoffPolicySet = false;
-
-        /**
-         * @param taskId Application-provided id for this task. Subsequent calls to cancel, or
-         *               tasks created with the same taskId, will update the pre-existing task with
-         *               the same id.
-         * @param taskService The endpoint that you implement that will receive the callback from the
-         *            TaskManager.
-         */
-        public Builder(int taskId, ComponentName taskService) {
-            mTaskService = taskService;
-            mTaskId = taskId;
-        }
-
-        /**
-         * Set optional extras. This is persisted, so we only allow primitive types.
-         * @param extras Bundle containing extras you want the scheduler to hold on to for you.
-         */
-        public Builder setExtras(Bundle extras) {
-            mExtras = extras;
-            return this;
-        }
-
-        /**
-         * Set some description of the kind of network capabilities you would like to have. This
-         * will be a parameter defined in {@link android.content.Task.NetworkType}.
-         * Not calling this function means the network is not necessary.
-         * Bear in mind that calling this function defines network as a strict requirement for your
-         * task if the network requested is not available your task will never run. See
-         * {@link #setOverrideDeadline(long)} to change this behaviour.
-         */
-        public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
-            mNetworkCapabilities = networkCapabilities;
-            return this;
-        }
-
-        /*
-         * Specify that to run this task, the device needs to be plugged in. This defaults to
-         * false.
-         * @param requireCharging Whether or not the device is plugged in.
-         */
-        public Builder setRequiresCharging(boolean requiresCharging) {
-            mRequiresCharging = requiresCharging;
-            return this;
-        }
-
-        /**
-         * Specify that to run, the task needs the device to be in idle mode. This defaults to
-         * false.
-         * <p>Idle mode is a loose definition provided by the system, which means that the device
-         * is not in use, and has not been in use for some time. As such, it is a good time to
-         * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
-         * to your application, and surfaced to the user in battery stats.</p>
-         * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
-         *                           window.
-         */
-        public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
-            mRequiresDeviceIdle = requiresDeviceIdle;
-            return this;
-        }
-
-        /**
-         * Specify that this task should recur with the provided interval, not more than once per
-         * period. You have no control over when within this interval this task will be executed,
-         * only the guarantee that it will be executed at most once within this interval.
-         * A periodic task will be repeated until the phone is turned off, however it will only be
-         * persisted beyond boot if the client app has declared the
-         * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
-         * periodic tasks without this permission, they simply will cease to exist after the phone
-         * restarts.
-         * Setting this function on the builder with {@link #setMinimumLatency(long)} or
-         * {@link #setOverrideDeadline(long)} will result in an error.
-         * @param intervalMillis Millisecond interval for which this task will repeat.
-         */
-        public Builder setPeriodic(long intervalMillis) {
-            mIsPeriodic = true;
-            mIntervalMillis = intervalMillis;
-            return this;
-        }
-
-        /**
-         * Specify that this task should be delayed by the provided amount of time.
-         * Because it doesn't make sense setting this property on a periodic task, doing so will
-         * throw an {@link java.lang.IllegalArgumentException} when
-         * {@link android.content.Task.Builder#build()} is called.
-         * @param minLatencyMillis Milliseconds before which this task will not be considered for
-         *                         execution.
-         */
-        public Builder setMinimumLatency(long minLatencyMillis) {
-            mMinLatencyMillis = minLatencyMillis;
-            return this;
-        }
-
-        /**
-         * Set deadline which is the maximum scheduling latency. The task will be run by this
-         * deadline even if other requirements are not met. Because it doesn't make sense setting
-         * this property on a periodic task, doing so will throw an
-         * {@link java.lang.IllegalArgumentException} when
-         * {@link android.content.Task.Builder#build()} is called.
-         */
-        public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
-            mMaxExecutionDelayMillis = maxExecutionDelayMillis;
-            return this;
-        }
-
-        /**
-         * Set up the back-off/retry policy.
-         * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
-         * 1hr.
-         * Note that trying to set a backoff criteria for a task with
-         * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
-         * This is because back-off typically does not make sense for these types of tasks. See
-         * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
-         * for more description of the return value for the case of a task executing while in idle
-         * mode.
-         * @param initialBackoffMillis Millisecond time interval to wait initially when task has
-         *                             failed.
-         * @param backoffPolicy is one of {@link BackoffPolicy}
-         */
-        public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
-            mBackoffPolicySet = true;
-            mInitialBackoffMillis = initialBackoffMillis;
-            mBackoffPolicy = backoffPolicy;
-            return this;
-        }
-
-        /**
-         * @return The task object to hand to the TaskManager. This object is immutable.
-         */
-        public Task build() {
-            // Check that extras bundle only contains primitive types.
-            try {
-                for (String key : extras.keySet()) {
-                    Object value = extras.get(key);
-                    if (value == null) continue;
-                    if (value instanceof Long) continue;
-                    if (value instanceof Integer) continue;
-                    if (value instanceof Boolean) continue;
-                    if (value instanceof Float) continue;
-                    if (value instanceof Double) continue;
-                    if (value instanceof String) continue;
-                    throw new IllegalArgumentException("Unexpected value type: "
-                            + value.getClass().getName());
-                }
-            } catch (IllegalArgumentException e) {
-                throw e;
-            } catch (RuntimeException exc) {
-                throw new IllegalArgumentException("error unparcelling Bundle", exc);
-            }
-            // Check that a deadline was not set on a periodic task.
-            if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
-                throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
-                        "periodic task.");
-            }
-            if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
-                throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
-                        "periodic task");
-            }
-            if (mBackoffPolicySet && mRequiresDeviceIdle) {
-                throw new IllegalArgumentException("An idle mode task will not respect any" +
-                        " back-off policy, so calling setBackoffCriteria with" +
-                        " setRequiresDeviceIdle is an error.");
-            }
-            return new Task(this);
-        }
-    }
-
-}
diff --git a/core/java/android/content/TaskManager.java b/core/java/android/content/TaskManager.java
deleted file mode 100644
index d28d78a..0000000
--- a/core/java/android/content/TaskManager.java
+++ /dev/null
@@ -1,66 +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.content;
-
-import java.util.List;
-
-/**
- * Class for scheduling various types of tasks with the scheduling framework on the device.
- *
- * Get an instance of this class through {@link Context#getSystemService(String)}.
- */
-public abstract class TaskManager {
-    /*
-     * Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
-     * if the run-time for your task is too short, or perhaps the system can't resolve the
-     * requisite {@link TaskService} in your package.
-     */
-    static final int RESULT_INVALID_PARAMETERS = -1;
-    /**
-     * Returned from {@link #schedule(Task)} if this application has made too many requests for
-     * work over too short a time.
-     */
-    // TODO: Determine if this is necessary.
-    static final int RESULT_OVER_QUOTA = -2;
-
-    /*
-     * @param task The task you wish scheduled. See {@link Task#TaskBuilder} for more detail on
-     * the sorts of tasks you can schedule.
-     * @return If >0, this int corresponds to the taskId of the successfully scheduled task.
-     * Otherwise you have to compare the return value to the error codes defined in this class.
-     */
-    public abstract int schedule(Task task);
-
-    /**
-     * Cancel a task that is pending in the TaskManager.
-     * @param taskId unique identifier for this task. Obtain this value from the tasks returned by
-     * {@link #getAllPendingTasks()}.
-     * @return
-     */
-    public abstract void cancel(int taskId);
-
-    /**
-     * Cancel all tasks that have been registered with the TaskManager by this package.
-     */
-    public abstract void cancelAll();
-
-    /**
-     * @return a list of all the tasks registered by this package that have not yet been executed.
-     */
-    public abstract List<Task> getAllPendingTasks();
-
-}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6cb781f..44a6a5d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -112,7 +112,7 @@
 
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
 
-    boolean canForwardTo(in Intent intent, String resolvedType, int userIdFrom, int userIdDest);
+    boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
 
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
             String resolvedType, int flags, int userId);
@@ -248,10 +248,10 @@
 
     void clearPackagePersistentPreferredActivities(String packageName, int userId);
 
-    void addForwardingIntentFilter(in IntentFilter filter, boolean removable, int userIdOrig,
-            int userIdDest);
+    void addCrossProfileIntentFilter(in IntentFilter filter, boolean removable, int sourceUserId,
+            int targetUserId);
 
-    void clearForwardingIntentFilters(int userIdOrig);
+    void clearCrossProfileIntentFilters(int sourceUserId);
 
     /**
      * Report the set of 'Home' activity candidates, plus (if any) which of them
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 35bcc02..c5cd5c9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3576,24 +3576,38 @@
     }
 
     /**
-     * Adds a forwarding intent filter. After calling this method all intents sent from the user
-     * with id userIdOrig can also be be resolved by activities in the user with id userIdDest if
-     * they match the specified intent filter.
-     * @param filter the {@link IntentFilter} the intent has to match to be forwarded
-     * @param removable if set to false, {@link clearForwardingIntents} will not remove this intent
-     * filter
-     * @param userIdOrig user from which the intent can be forwarded
-     * @param userIdDest user to which the intent can be forwarded
+     * 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}
      * @hide
      */
-    public abstract void addForwardingIntentFilter(IntentFilter filter, boolean removable,
-            int userIdOrig, int userIdDest);
+    public abstract void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
+            int sourceUserId, int targetUserId);
 
     /**
-     * Clearing all removable {@link ForwardingIntentFilter}s that are set with the given user as
-     * the origin.
-     * @param userIdOrig user from which the intent can be forwarded
+     * @hide
+     * @deprecated
+     * TODO: remove it as soon as the code of ManagedProvisionning is updated
+    */
+    public abstract void addForwardingIntentFilter(IntentFilter filter, boolean removable,
+            int sourceUserId, int targetUserId);
+
+    /**
+     * Clearing removable {@link CrossProfileIntentFilter}s which have the specified user as their
+     * source
+     * @param sourceUserId
+     * be cleared.
      * @hide
      */
-    public abstract void clearForwardingIntentFilters(int userIdOrig);
+    public abstract void clearCrossProfileIntentFilters(int sourceUserId);
+
+    /**
+     * @hide
+     * @deprecated
+     * TODO: remove it as soon as the code of ManagedProvisionning is updated
+    */
+    public abstract void clearForwardingIntentFilters(int sourceUserId);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 1c838c3..ab8bf61 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2174,7 +2174,6 @@
         }
 
         final int innerDepth = parser.getDepth();
-
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
@@ -2548,13 +2547,13 @@
                     com.android.internal.R.styleable.AndroidManifestActivity_singleUser,
                     false)) {
                 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
-                if (a.info.exported) {
+                if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
                     Slog.w(TAG, "Activity exported request ignored due to singleUser: "
                             + a.className + " at " + mArchiveSourcePath + " "
                             + parser.getPositionDescription());
                     a.info.exported = false;
+                    setExported = true;
                 }
-                setExported = true;
             }
             if (sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly,
@@ -2907,7 +2906,7 @@
                 com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
                 false)) {
             p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
-            if (p.info.exported) {
+            if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
                 Slog.w(TAG, "Provider exported request ignored due to singleUser: "
                         + p.className + " at " + mArchiveSourcePath + " "
                         + parser.getPositionDescription());
@@ -3181,13 +3180,13 @@
                 com.android.internal.R.styleable.AndroidManifestService_singleUser,
                 false)) {
             s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
-            if (s.info.exported) {
+            if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
                 Slog.w(TAG, "Service exported request ignored due to singleUser: "
                         + s.className + " at " + mArchiveSourcePath + " "
                         + parser.getPositionDescription());
                 s.info.exported = false;
+                setExported = true;
             }
-            setExported = true;
         }
 
         sa.recycle();
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index a78f8e2..3737638 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -31,11 +31,11 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Trace;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.util.TypedValue;
 import android.util.LongSparseArray;
 
@@ -104,10 +104,10 @@
     // These are protected by mAccessLock.
     private final Object mAccessLock = new Object();
     private final Configuration mTmpConfig = new Configuration();
-    private final ThemedCaches<ConstantState> mDrawableCache =
-            new ThemedCaches<ConstantState>();
-    private final ThemedCaches<ConstantState> mColorDrawableCache =
-            new ThemedCaches<ConstantState>();
+    private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mDrawableCache =
+            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
+    private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache =
+            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
     private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache =
             new LongSparseArray<WeakReference<ColorStateList>>();
 
@@ -1261,18 +1261,17 @@
          * any of the style's attributes are already defined in the theme, the
          * current values in the theme will be overwritten.
          * 
-         * @param resid The resource ID of a style resource from which to
+         * @param resId The resource ID of a style resource from which to
          *              obtain attribute values.
          * @param force If true, values in the style resource will always be
          *              used in the theme; otherwise, they will only be used
          *              if not already defined in the theme.
          */
-        public void applyStyle(int resid, boolean force) {
-            AssetManager.applyThemeStyle(mTheme, resid, force);
+        public void applyStyle(int resId, boolean force) {
+            AssetManager.applyThemeStyle(mTheme, resId, force);
 
-            // TODO: In very rare cases, we may end up with a hybrid theme
-            // that can't map to a single theme ID.
-            mThemeResId = resid;
+            mThemeResId = resId;
+            mKey += Integer.toHexString(resId) + (force ? "! " : " ");
         }
 
         /**
@@ -1288,6 +1287,7 @@
             AssetManager.copyTheme(mTheme, other.mTheme);
 
             mThemeResId = other.mThemeResId;
+            mKey = other.mKey;
         }
 
         /**
@@ -1577,6 +1577,9 @@
         /** Resource identifier for the theme. */
         private int mThemeResId = 0;
 
+        /** Unique key for the series of styles applied to this theme. */
+        private String mKey = "";
+
         // Needed by layoutlib.
         /*package*/ long getNativeTheme() {
             return mTheme;
@@ -1585,6 +1588,10 @@
         /*package*/ int getAppliedStyleResId() {
             return mThemeResId;
         }
+
+        /*package*/ String getKey() {
+            return mKey;
+        }
     }
 
     /**
@@ -1740,7 +1747,8 @@
     }
 
     private void clearDrawableCachesLocked(
-            ThemedCaches<ConstantState> caches, int configChanges) {
+            ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
+            int configChanges) {
         final int N = caches.size();
         for (int i = 0; i < N; i++) {
             clearDrawableCacheLocked(caches.valueAt(i), configChanges);
@@ -1763,7 +1771,7 @@
                             configChanges, cs.getChangingConfigurations())) {
                         if (DEBUG_CONFIG) {
                             Log.d(TAG, "FLUSHING #0x"
-                                    + Long.toHexString(mDrawableCache.keyAt(i))
+                                    + Long.toHexString(cache.keyAt(i))
                                     + " / " + cs + " with changes: 0x"
                                     + Integer.toHexString(cs.getChangingConfigurations()));
                         }
@@ -2205,7 +2213,7 @@
         }
 
         final boolean isColorDrawable;
-        final ThemedCaches<ConstantState> caches;
+        final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches;
         final long key;
         if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
                 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
@@ -2258,7 +2266,8 @@
     }
 
     private void cacheDrawable(TypedValue value, Theme theme, boolean isColorDrawable,
-            ThemedCaches<ConstantState> caches, long key, Drawable dr) {
+            ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
+            long key, Drawable dr) {
         final ConstantState cs = dr.getConstantState();
         if (cs == null) {
             return;
@@ -2287,8 +2296,12 @@
             }
         } else {
             synchronized (mAccessLock) {
-                final LongSparseArray<WeakReference<ConstantState>> themedCache;
-                themedCache = caches.getOrCreate(theme == null ? 0 : theme.mThemeResId);
+                final String themeKey = theme == null ? "" : theme.mKey;
+                LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey);
+                if (themedCache == null) {
+                    themedCache = new LongSparseArray<WeakReference<ConstantState>>(1);
+                    caches.put(themeKey, themedCache);
+                }
                 themedCache.put(key, new WeakReference<ConstantState>(cs));
             }
         }
@@ -2347,7 +2360,9 @@
         return dr;
     }
 
-    private Drawable getCachedDrawable(ThemedCaches<ConstantState> caches, long key, Theme theme) {
+    private Drawable getCachedDrawable(
+            ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
+            long key, Theme theme) {
         synchronized (mAccessLock) {
             final int themeKey = theme != null ? theme.mThemeResId : 0;
             final LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey);
@@ -2584,21 +2599,4 @@
         updateConfiguration(null, null);
         mAssets.ensureStringBlocks();
     }
-
-    static class ThemedCaches<T> extends SparseArray<LongSparseArray<WeakReference<T>>> {
-        /**
-         * Returns the cache of drawables styled for the specified theme.
-         * <p>
-         * Drawables that have themeable attributes but were loaded without
-         * specifying a theme are cached at themeResId = 0.
-         */
-        public LongSparseArray<WeakReference<T>> getOrCreate(int themeResId) {
-            LongSparseArray<WeakReference<T>> result = get(themeResId);
-            if (result == null) {
-                result = new LongSparseArray<WeakReference<T>>(1);
-                put(themeResId, result);
-            }
-            return result;
-        }
-    }
 }
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index c593e9e..c8de2f1 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -142,9 +142,10 @@
     public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
 
     /**
-     * A constant describing a proximity sensor type.
+     * A constant describing a proximity sensor type. This is a wake up sensor.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
+     * @see #isWakeUpSensor()
      */
     public static final int TYPE_PROXIMITY = 8;
 
@@ -307,8 +308,10 @@
      * itself. The sensor continues to operate while the device is asleep
      * and will automatically wake the device to notify when significant
      * motion is detected. The application does not need to hold any wake
-     * locks for this sensor to trigger.
+     * locks for this sensor to trigger. This is a wake up sensor.
      * <p>See {@link TriggerEvent} for more details.
+     *
+     * @see #isWakeUpSensor()
      */
     public static final int TYPE_SIGNIFICANT_MOTION = 17;
 
@@ -381,11 +384,17 @@
     /**
      * A constant describing a heart rate monitor.
      * <p>
-     * A sensor that measures the heart rate in beats per minute.
+     * The reported value is the heart rate in beats per minute.
      * <p>
-     * value[0] represents the beats per minute when the measurement was taken.
-     * value[0] is 0 if the heart rate monitor could not measure the rate or the
-     * rate is 0 beat per minute.
+     * The reported accuracy represents the status of the monitor during the reading. See the
+     * {@code SENSOR_STATUS_*} constants in {@link android.hardware.SensorManager SensorManager}
+     * for more details on accuracy/status values. In particular, when the accuracy is
+     * {@code SENSOR_STATUS_UNRELIABLE} or {@code SENSOR_STATUS_NO_CONTACT}, the heart rate
+     * value should be discarded.
+     * <p>
+     * This sensor requires permission {@code android.permission.BODY_SENSORS}.
+     * It will not be returned by {@code SensorManager.getSensorsList} nor
+     * {@code SensorManager.getDefaultSensor} if the application doesn't have this permission.
      */
     public static final int TYPE_HEART_RATE = 21;
 
@@ -397,6 +406,321 @@
     public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
 
     /**
+     * A non-wake up variant of proximity sensor.
+     *
+     * @see #TYPE_PROXIMITY
+     */
+    public static final int TYPE_NON_WAKE_UP_PROXIMITY_SENSOR = 22;
+
+    /**
+     * A constant string describing a non-wake up proximity sensor type.
+     *
+     * @see #TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
+     */
+    public static final String SENSOR_STRING_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR =
+            "android.sensor.non_wake_up_proximity_sensor";
+
+    /**
+     * A constant describing a wake up variant of accelerometer sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_ACCELEROMETER
+     */
+    public static final int TYPE_WAKE_UP_ACCELEROMETER = 23;
+
+    /**
+     * A constant string describing a wake up accelerometer.
+     *
+     * @see #TYPE_WAKE_UP_ACCELEROMETER
+     */
+    public static final String STRING_TYPE_WAKE_UP_ACCELEROMETER =
+            "android.sensor.wake_up_accelerometer";
+
+    /**
+     * A constant describing a wake up variant of a magnetic field sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_MAGNETIC_FIELD
+     */
+    public static final int TYPE_WAKE_UP_MAGNETIC_FIELD = 24;
+
+    /**
+     * A constant string describing a wake up magnetic field sensor.
+     *
+     * @see #TYPE_WAKE_UP_MAGNETIC_FIELD
+     */
+    public static final String STRING_TYPE_WAKE_UP_MAGNETIC_FIELD =
+            "android.sensor.wake_up_magnetic_field";
+
+    /**
+     * A constant describing a wake up variant of an orientation sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_ORIENTATION
+     */
+    public static final int TYPE_WAKE_UP_ORIENTATION = 25;
+
+    /**
+     * A constant string describing a wake up orientation sensor.
+     *
+     * @see #TYPE_WAKE_UP_ORIENTATION
+     */
+    public static final String STRING_TYPE_WAKE_UP_ORIENTATION =
+            "android.sensor.wake_up_orientation";
+
+    /**
+     * A constant describing a wake up variant of a gyroscope sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_GYROSCOPE
+     */
+    public static final int TYPE_WAKE_UP_GYROSCOPE = 26;
+
+    /**
+     * A constant string describing a wake up gyroscope sensor type.
+     *
+     * @see #TYPE_WAKE_UP_GYROSCOPE
+     */
+    public static final String STRING_TYPE_WAKE_UP_GYROSCOPE = "android.sensor.wake_up_gyroscope";
+
+    /**
+     * A constant describing a wake up variant of a light sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_LIGHT
+     */
+    public static final int TYPE_WAKE_UP_LIGHT = 27;
+
+    /**
+     * A constant string describing a wake up light sensor type.
+     *
+     * @see #TYPE_WAKE_UP_LIGHT
+     */
+    public static final String STRING_TYPE_WAKE_UP_LIGHT = "android.sensor.wake_up_light";
+
+    /**
+     * A constant describing a wake up variant of a pressure sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_PRESSURE
+     */
+    public static final int TYPE_WAKE_UP_PRESSURE = 28;
+
+    /**
+     * A constant string describing a wake up pressure sensor type.
+     *
+     * @see #TYPE_WAKE_UP_PRESSURE
+     */
+    public static final String STRING_TYPE_WAKE_UP_PRESSURE = "android.sensor.wake_up_pressure";
+
+    /**
+     * A constant describing a wake up variant of a gravity sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_GRAVITY
+     */
+    public static final int TYPE_WAKE_UP_GRAVITY = 29;
+
+    /**
+     * A constant string describing a wake up gravity sensor type.
+     *
+     * @see #TYPE_WAKE_UP_GRAVITY
+     */
+    public static final String STRING_TYPE_WAKE_UP_GRAVITY = "android.sensor.wake_up_gravity";
+
+    /**
+     * A constant describing a wake up variant of a linear acceleration sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_LINEAR_ACCELERATION
+     */
+    public static final int TYPE_WAKE_UP_LINEAR_ACCELERATION = 30;
+
+    /**
+     * A constant string describing a wake up linear acceleration sensor type.
+     *
+     * @see #TYPE_WAKE_UP_LINEAR_ACCELERATION
+     */
+    public static final String STRING_TYPE_WAKE_UP_LINEAR_ACCELERATION =
+            "android.sensor.wake_up_linear_acceleration";
+
+    /**
+     * A constant describing a wake up variant of a rotation vector sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_ROTATION_VECTOR
+     */
+    public static final int TYPE_WAKE_UP_ROTATION_VECTOR = 31;
+
+    /**
+     * A constant string describing a wake up rotation vector sensor type.
+     *
+     * @see #TYPE_WAKE_UP_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_WAKE_UP_ROTATION_VECTOR =
+            "android.sensor.wake_up_rotation_vector";
+
+    /**
+     * A constant describing a wake up variant of a relative humidity sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_RELATIVE_HUMIDITY
+     */
+    public static final int TYPE_WAKE_UP_RELATIVE_HUMIDITY = 32;
+
+    /**
+     * A constant string describing a wake up relative humidity sensor type.
+     *
+     * @see #TYPE_WAKE_UP_RELATIVE_HUMIDITY
+     */
+    public static final String STRING_TYPE_WAKE_UP_RELATIVE_HUMIDITY =
+            "android.sensor.wake_up_relative_humidity";
+
+    /**
+     * A constant describing a wake up variant of an ambient temperature sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_AMBIENT_TEMPERATURE
+     */
+    public static final int TYPE_WAKE_UP_AMBIENT_TEMPERATURE = 33;
+
+    /**
+     * A constant string describing a wake up ambient temperature sensor type.
+     *
+     * @see #TYPE_WAKE_UP_AMBIENT_TEMPERATURE
+     */
+    public static final String STRING_TYPE_WAKE_UP_AMBIENT_TEMPERATURE =
+            "android.sensor.wake_up_ambient_temperature";
+
+    /**
+     * A constant describing a wake up variant of an uncalibrated magnetic field sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
+     */
+    public static final int TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED = 34;
+
+    /**
+     * A constant string describing a wake up uncalibrated magnetic field sensor type.
+     *
+     * @see #TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED =
+            "android.sensor.wake_up_magnetic_field_uncalibrated";
+
+    /**
+     * A constant describing a wake up variant of a game rotation vector sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_GAME_ROTATION_VECTOR
+     */
+    public static final int TYPE_WAKE_UP_GAME_ROTATION_VECTOR = 35;
+
+    /**
+     * A constant string describing a wake up game rotation vector sensor type.
+     *
+     * @see #TYPE_WAKE_UP_GAME_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_WAKE_UP_GAME_ROTATION_VECTOR =
+            "android.sensor.wake_up_game_rotation_vector";
+
+    /**
+     * A constant describing a wake up variant of an uncalibrated gyroscope sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_GYROSCOPE_UNCALIBRATED
+     */
+    public static final int TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED = 36;
+
+    /**
+     * A constant string describing a wake up uncalibrated gyroscope sensor type.
+     *
+     * @see #TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED =
+            "android.sensor.wake_up_gyroscope_uncalibrated";
+
+    /**
+     * A constant describing a wake up variant of a step detector sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_STEP_DETECTOR
+     */
+    public static final int TYPE_WAKE_UP_STEP_DETECTOR = 37;
+
+    /**
+     * A constant string describing a wake up step detector sensor type.
+     *
+     * @see #TYPE_WAKE_UP_STEP_DETECTOR
+     */
+    public static final String STRING_TYPE_WAKE_UP_STEP_DETECTOR =
+            "android.sensor.wake_up_step_detector";
+
+    /**
+     * A constant describing a wake up variant of a step counter sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_STEP_COUNTER
+     */
+    public static final int TYPE_WAKE_UP_STEP_COUNTER = 38;
+
+    /**
+     * A constant string describing a wake up step counter sensor type.
+     *
+     * @see #TYPE_WAKE_UP_STEP_COUNTER
+     */
+    public static final String STRING_TYPE_WAKE_UP_STEP_COUNTER =
+            "android.sensor.wake_up_step_counter";
+
+    /**
+     * A constant describing a wake up variant of a geomagnetic rotation vector sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
+     */
+    public static final int TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR = 39;
+
+    /**
+     * A constant string describing a wake up geomagnetic rotation vector sensor type.
+     *
+     * @see #TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR =
+            "android.sensor.wake_up_geomagnetic_rotation_vector";
+
+    /**
+     * A constant describing a wake up variant of a heart rate sensor type.
+     *
+     * @see #isWakeUpSensor()
+     * @see #TYPE_HEART_RATE
+     */
+    public static final int TYPE_WAKE_UP_HEART_RATE = 40;
+
+    /**
+     * A constant string describing a wake up heart rate sensor type.
+     *
+     * @see #TYPE_WAKE_UP_HEART_RATE
+     */
+    public static final String STRING_TYPE_WAKE_UP_HEART_RATE = "android.sensor.wake_up_heart_rate";
+
+    /**
+     * A sensor of this type generates an event each time a tilt event is detected. A tilt event
+     * is generated if the direction of the 2-seconds window average gravity changed by at
+     * least 35 degrees since the activation of the sensor. It is a wake up sensor.
+     *
+     * @see #isWakeUpSensor()
+     */
+    public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41;
+
+    /**
+     * A constant string describing a wake up tilt detector sensor type.
+     *
+     * @see #TYPE_WAKE_UP_TILT_DETECTOR
+     */
+    public static final String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR =
+            "android.sensor.wake_up_tilt_detector";
+
+    /**
      * A constant describing a wake gesture sensor.
      * <p>
      * Wake gesture sensors enable waking up the device based on a device specific motion.
@@ -410,6 +734,7 @@
      * the device. This sensor must be low power, as it is likely to be activated 24/7.
      * Values of events created by this sensors should not be used.
      *
+     * @see #isWakeUpSensor()
      * @hide This sensor is expected to only be used by the power manager
      */
     public static final int TYPE_WAKE_GESTURE = 42;
@@ -467,7 +792,29 @@
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_DETECTOR
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_COUNTER
             REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
-            REPORTING_MODE_ON_CHANGE, 1  // SENSOR_TYPE_HEART_RATE_MONITOR
+            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_HEART_RATE_MONITOR
+            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
+            // wake up variants of base sensors
+            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ACCELEROMETER
+            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD
+            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ORIENTATION
+            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GYROSCOPE
+            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_WAKE_UP_LIGHT
+            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_PRESSURE
+            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GRAVITY
+            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION
+            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR
+            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY
+            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE
+            REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
+            REPORTING_MODE_CONTINUOUS, 4, // SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR
+            REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
+            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_STEP_DETECTOR
+            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_STEP_COUNTER
+            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
+            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_HEART_RATE_MONITOR
+            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
+            REPORTING_MODE_ONE_SHOT,   1, // SENSOR_TYPE_WAKE_GESTURE
     };
 
     static int getReportingMode(Sensor sensor) {
@@ -525,6 +872,8 @@
     private int     mFifoMaxEventCount;
     private String  mStringType;
     private String  mRequiredPermission;
+    private int     mMaxDelay;
+    private boolean mWakeUpSensor;
 
     Sensor() {
     }
@@ -625,6 +974,51 @@
         return mHandle;
     }
 
+    /**
+     * This value is defined only for continuous mode sensors. It is the delay between two
+     * sensor events corresponding to the lowest frequency that this sensor supports. When
+     * lower frequencies are requested through registerListener() the events will be generated
+     * at this frequency instead. It can be used to estimate when the batch FIFO may be full.
+     * Older devices may set this value to zero. Ignore this value in case it is negative
+     * or zero.
+     *
+     * @return The max delay for this sensor in microseconds.
+     */
+    public int getMaxDelay() {
+        return mMaxDelay;
+    }
+
+    /**
+     * Returns whether this sensor is a wake-up sensor.
+     * <p>
+     * Wake up sensors wake the application processor up when they have events to deliver. When a
+     * wake up sensor is registered to without batching enabled, each event will wake the
+     * application processor up.
+     * <p>
+     * When a wake up sensor is registered to with batching enabled, it
+     * wakes the application processor up when maxReportingLatency has elapsed or when the hardware
+     * FIFO storing the events from wake up sensors is getting full.
+     * <p>
+     * Non-wake up sensors never wake the application processor up. Their events are only reported
+     * when the application processor is awake, for example because the application holds a wake
+     * lock, or another source woke the application processor up.
+     * <p>
+     * When a non-wake up sensor is registered to without batching enabled, the measurements made
+     * while the application processor is asleep might be lost and never returned.
+     * <p>
+     * When a non-wake up sensor is registered to with batching enabled, the measurements made while
+     * the application processor is asleep are stored in the hardware FIFO for non-wake up sensors.
+     * When this FIFO gets full, new events start overwriting older events. When the application
+     * then wakes up, the latest events are returned, and some old events might be lost. The number
+     * of events actually returned depends on the hardware FIFO size, as well as on what other
+     * sensors are activated. If losing sensor events is not acceptable during batching, you must
+     * use the wake-up version of the sensor.
+     * @return true if this is a wake up sensor, false otherwise.
+     */
+    public boolean isWakeUpSensor() {
+        return mWakeUpSensor;
+    }
+
     void setRange(float max, float res) {
         mMaxRange = max;
         mResolution = res;
diff --git a/core/java/android/hardware/SensorEventListener.java b/core/java/android/hardware/SensorEventListener.java
index 677d244..0d859fb 100644
--- a/core/java/android/hardware/SensorEventListener.java
+++ b/core/java/android/hardware/SensorEventListener.java
@@ -39,11 +39,13 @@
     public void onSensorChanged(SensorEvent event);
 
     /**
-     * Called when the accuracy of a sensor has changed.
-     * <p>See {@link android.hardware.SensorManager SensorManager}
-     * for details.
+     * Called when the accuracy of the registered sensor has changed.
      *
-     * @param accuracy The new accuracy of this sensor
+     * <p>See the SENSOR_STATUS_* constants in
+     * {@link android.hardware.SensorManager SensorManager} for details.
+     *
+     * @param accuracy The new accuracy of this sensor, one of
+     *         {@code SensorManager.SENSOR_STATUS_*}
      */
-    public void onAccuracyChanged(Sensor sensor, int accuracy);    
+    public void onAccuracyChanged(Sensor sensor, int accuracy);
 }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 5f2b5f0..25c7630 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -321,6 +321,13 @@
 
 
     /**
+      * The values returned by this sensor cannot be trusted because the sensor
+      * had no contact with what it was measuring (for example, the heart rate
+      * monitor is not in contact with the user).
+      */
+    public static final int SENSOR_STATUS_NO_CONTACT = -1;
+
+    /**
      * The values returned by this sensor cannot be trusted, calibration is
      * needed or the environment doesn't allow readings
      */
@@ -421,9 +428,10 @@
      * {@link SensorManager#getSensorList(int) getSensorList}.
      *
      * @param type
-     *        of sensors requested
+     *         of sensors requested
      *
-     * @return the default sensors matching the asked type.
+     * @return the default sensor matching the requested type if one exists and the application
+     *         has the necessary permissions, or null otherwise.
      *
      * @see #getSensorList(int)
      * @see Sensor
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 8684a04..b66ec86 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -395,25 +395,12 @@
             t.timestamp = timestamp;
             t.accuracy = inAccuracy;
             t.sensor = sensor;
-            switch (t.sensor.getType()) {
-                // Only report accuracy for sensors that support it.
-                case Sensor.TYPE_MAGNETIC_FIELD:
-                case Sensor.TYPE_ORIENTATION:
-                    // call onAccuracyChanged() only if the value changes
-                    final int accuracy = mSensorAccuracies.get(handle);
-                    if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
-                        mSensorAccuracies.put(handle, t.accuracy);
-                        mListener.onAccuracyChanged(t.sensor, t.accuracy);
-                    }
-                    break;
-                default:
-                    // For other sensors, just report the accuracy once
-                    if (mFirstEvent.get(handle) == false) {
-                        mFirstEvent.put(handle, true);
-                        mListener.onAccuracyChanged(
-                                t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
-                    }
-                    break;
+
+            // call onAccuracyChanged() only if the value changes
+            final int accuracy = mSensorAccuracies.get(handle);
+            if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
+                mSensorAccuracies.put(handle, t.accuracy);
+                mListener.onAccuracyChanged(t.sensor, t.accuracy);
             }
             mListener.onSensorChanged(t);
         }
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
index 1af575f..ca71e81 100644
--- a/core/java/android/hardware/camera2/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -114,7 +114,10 @@
         mReason = problem;
     }
 
-    private static String getDefaultMessage(int problem) {
+    /**
+     * @hide
+     */
+    public static String getDefaultMessage(int problem) {
         switch (problem) {
             case CAMERA_IN_USE:
                 return "The camera device is in use already";
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 8391209..7738d2d 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -508,14 +508,62 @@
         }
 
         /**
-         * This method is called when an image capture has completed and the
-         * result metadata is available.
+         * This method is called when an image capture makes partial forward progress; some
+         * (but not all) results from an image capture are available.
+         *
+         * <p>The result provided here will contain some subset of the fields of
+         * a full result. Multiple {@link #onCaptureProgressed} calls may happen per
+         * capture; a given result field will only be present in one partial
+         * capture at most. The final {@link #onCaptureCompleted} call will always
+         * contain all the fields (in particular, the union of all the fields of all
+         * the partial results composing the total result).</p>
+         *
+         * <p>For each request, some result data might be available earlier than others. The typical
+         * delay between each partial result (per request) is a single frame interval.
+         * For performance-oriented use-cases, applications should query the metadata they need
+         * to make forward progress from the partial results and avoid waiting for the completed
+         * result.</p>
+         *
+         * <p>Each request will generate at least {@code 1} partial results, and at most
+         * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p>
+         *
+         * <p>Depending on the request settings, the number of partial results per request
+         * will vary, although typically the partial count could be the same as long as the
+         * camera device subsystems enabled stay the same.</p>
          *
          * <p>The default implementation of this method does nothing.</p>
          *
          * @param camera The CameraDevice sending the callback.
          * @param request The request that was given to the CameraDevice
-         * @param result The output metadata from the capture, including the
+         * @param partialResult The partial output metadata from the capture, which
+         * includes a subset of the {@link TotalCaptureResult} fields.
+         *
+         * @see #capture
+         * @see #captureBurst
+         * @see #setRepeatingRequest
+         * @see #setRepeatingBurst
+         */
+        public void onCaptureProgressed(CameraDevice camera,
+                CaptureRequest request, CaptureResult partialResult) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called when an image capture has fully completed and all the
+         * result metadata is available.
+         *
+         * <p>This callback will always fire after the last {@link #onCaptureProgressed};
+         * in other words, no more partial results will be delivered once the completed result
+         * is available.</p>
+         *
+         * <p>For performance-intensive use-cases where latency is a factor, consider
+         * using {@link #onCaptureProgressed} instead.</p>
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param camera The CameraDevice sending the callback.
+         * @param request The request that was given to the CameraDevice
+         * @param result The total output metadata from the capture, including the
          * final capture parameters and the state of the camera system during
          * capture.
          *
@@ -525,7 +573,7 @@
          * @see #setRepeatingBurst
          */
         public void onCaptureCompleted(CameraDevice camera,
-                CaptureRequest request, CaptureResult result) {
+                CaptureRequest request, TotalCaptureResult result) {
             // default empty implementation
         }
 
@@ -563,24 +611,57 @@
          * when a capture sequence finishes and all {@link CaptureResult}
          * or {@link CaptureFailure} for it have been returned via this listener.
          *
+         * <p>In total, there will be at least one result/failure returned by this listener
+         * before this callback is invoked. If the capture sequence is aborted before any
+         * requests have been processed, {@link #onCaptureSequenceAborted} is invoked instead.</p>
+         *
+         * <p>The default implementation does nothing.</p>
+         *
          * @param camera
          *            The CameraDevice sending the callback.
          * @param sequenceId
          *            A sequence ID returned by the {@link #capture} family of functions.
-         * @param lastFrameNumber
+         * @param frameNumber
          *            The last frame number (returned by {@link CaptureResult#getFrameNumber}
          *            or {@link CaptureFailure#getFrameNumber}) in the capture sequence.
-         *            The last frame number may be equal to NO_FRAMES_CAPTURED if no images
-         *            were captured for this sequence. This can happen, for example, when a
-         *            repeating request or burst is cleared right after being set.
          *
          * @see CaptureResult#getFrameNumber()
          * @see CaptureFailure#getFrameNumber()
          * @see CaptureResult#getSequenceId()
          * @see CaptureFailure#getSequenceId()
+         * @see #onCaptureSequenceAborted
          */
         public void onCaptureSequenceCompleted(CameraDevice camera,
-                int sequenceId, int lastFrameNumber) {
+                int sequenceId, long frameNumber) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called independently of the others in CaptureListener,
+         * when a capture sequence aborts before any {@link CaptureResult}
+         * or {@link CaptureFailure} for it have been returned via this listener.
+         *
+         * <p>Due to the asynchronous nature of the camera device, not all submitted captures
+         * are immediately processed. It is possible to clear out the pending requests
+         * by a variety of operations such as {@link CameraDevice#stopRepeating} or
+         * {@link CameraDevice#flush}. When such an event happens,
+         * {@link #onCaptureSequenceCompleted} will not be called.</p>
+         *
+         * <p>The default implementation does nothing.</p>
+         *
+         * @param camera
+         *            The CameraDevice sending the callback.
+         * @param sequenceId
+         *            A sequence ID returned by the {@link #capture} family of functions.
+         *
+         * @see CaptureResult#getFrameNumber()
+         * @see CaptureFailure#getFrameNumber()
+         * @see CaptureResult#getSequenceId()
+         * @see CaptureFailure#getSequenceId()
+         * @see #onCaptureSequenceCompleted
+         */
+        public void onCaptureSequenceAborted(CameraDevice camera,
+                int sequenceId) {
             // default empty implementation
         }
     }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 164e683..c08424a 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -16,7 +16,9 @@
 
 package android.hardware.camera2;
 
+import android.hardware.camera2.CaptureResult.Key;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.TypeReference;
 import android.util.Rational;
 
 import java.util.Collections;
@@ -35,18 +37,109 @@
  * @see CameraDevice
  * @see CameraManager
  */
-public final class CameraCharacteristics extends CameraMetadata {
+public final class CameraCharacteristics extends CameraMetadata<CameraCharacteristics.Key<?>> {
+
+    /**
+     * A {@code Key} is used to do camera characteristics field lookups with
+     * {@link CameraCharacteristics#get}.
+     *
+     * <p>For example, to get the stream configuration map:
+     * <code><pre>
+     * StreamConfigurationMap map = cameraCharacteristics.get(
+     *      CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+     * </pre></code>
+     * </p>
+     *
+     * <p>To enumerate over all possible keys for {@link CameraCharacteristics}, see
+     * {@link CameraCharacteristics#getKeys()}.</p>
+     *
+     * @see CameraCharacteristics#get
+     * @see CameraCharacteristics#getKeys()
+     */
+    public static final class Key<T> {
+        private final CameraMetadataNative.Key<T> mKey;
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
+        public Key(String name, Class<T> type) {
+            mKey = new CameraMetadataNative.Key<T>(name,  type);
+        }
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
+        public Key(String name, TypeReference<T> typeReference) {
+            mKey = new CameraMetadataNative.Key<T>(name,  typeReference);
+        }
+
+        /**
+         * Return a camelCase, period separated name formatted like:
+         * {@code "root.section[.subsections].name"}.
+         *
+         * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
+         * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
+         *
+         * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
+         * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
+         * specific key might look like {@code "com.google.nexus.data.private"}.</p>
+         *
+         * @return String representation of the key name
+         */
+        public String getName() {
+            return mKey.getName();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public final int hashCode() {
+            return mKey.hashCode();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public final boolean equals(Object o) {
+            return o instanceof Key && ((Key<T>)o).mKey.equals(mKey);
+        }
+
+        /**
+         * Visible for CameraMetadataNative implementation only; do not use.
+         *
+         * TODO: Make this private or remove it altogether.
+         *
+         * @hide
+         */
+        public CameraMetadataNative.Key<T> getNativeKey() {
+            return mKey;
+        }
+
+        @SuppressWarnings({
+                "unused", "unchecked"
+        })
+        private Key(CameraMetadataNative.Key<?> nativeKey) {
+            mKey = (CameraMetadataNative.Key<T>) nativeKey;
+        }
+    }
 
     private final CameraMetadataNative mProperties;
-    private List<Key<?>> mAvailableRequestKeys;
-    private List<Key<?>> mAvailableResultKeys;
+    private List<CaptureRequest.Key<?>> mAvailableRequestKeys;
+    private List<CaptureResult.Key<?>> mAvailableResultKeys;
 
     /**
      * Takes ownership of the passed-in properties object
      * @hide
      */
     public CameraCharacteristics(CameraMetadataNative properties) {
-        mProperties = properties;
+        mProperties = CameraMetadataNative.move(properties);
     }
 
     /**
@@ -57,12 +150,55 @@
         return new CameraMetadataNative(mProperties);
     }
 
-    @Override
+    /**
+     * Get a camera characteristics field value.
+     *
+     * <p>The field definitions can be
+     * found in {@link CameraCharacteristics}.</p>
+     *
+     * <p>Querying the value for the same key more than once will return a value
+     * which is equal to the previous queried value.</p>
+     *
+     * @throws IllegalArgumentException if the key was not valid
+     *
+     * @param key The characteristics field to read.
+     * @return The value of that key, or {@code null} if the field is not set.
+     */
     public <T> T get(Key<T> key) {
         return mProperties.get(key);
     }
 
     /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected <T> T getProtected(Key<?> key) {
+        return (T) mProperties.get(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class<Key<?>> getKeyClass() {
+        Object thisClass = Key.class;
+        return (Class<Key<?>>)thisClass;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Key<?>> getKeys() {
+        // Force the javadoc for this function to show up on the CameraCharacteristics page
+        return super.getKeys();
+    }
+
+    /**
      * Returns the list of keys supported by this {@link CameraDevice} for querying
      * with a {@link CaptureRequest}.
      *
@@ -76,9 +212,14 @@
      *
      * @return List of keys supported by this CameraDevice for CaptureRequests.
      */
-    public List<Key<?>> getAvailableCaptureRequestKeys() {
+    @SuppressWarnings({"unchecked"})
+    public List<CaptureRequest.Key<?>> getAvailableCaptureRequestKeys() {
         if (mAvailableRequestKeys == null) {
-            mAvailableRequestKeys = getAvailableKeyList(CaptureRequest.class);
+            Object crKey = CaptureRequest.Key.class;
+            Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;
+
+            mAvailableRequestKeys = Collections.unmodifiableList(
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped));
         }
         return mAvailableRequestKeys;
     }
@@ -97,9 +238,14 @@
      *
      * @return List of keys supported by this CameraDevice for CaptureResults.
      */
-    public List<Key<?>> getAvailableCaptureResultKeys() {
+    @SuppressWarnings({"unchecked"})
+    public List<CaptureResult.Key<?>> getAvailableCaptureResultKeys() {
         if (mAvailableResultKeys == null) {
-            mAvailableResultKeys = getAvailableKeyList(CaptureResult.class);
+            Object crKey = CaptureResult.Key.class;
+            Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>)crKey;
+
+            mAvailableResultKeys = Collections.unmodifiableList(
+                    getAvailableKeyList(CaptureResult.class, crKeyTyped));
         }
         return mAvailableResultKeys;
     }
@@ -113,12 +259,14 @@
      * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
      *
      * @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
+     * @param keyClass The class of the metadata key, e.g. CaptureRequest.Key.class
      *
      * @return List of keys supported by this CameraDevice for metadataClass.
      *
      * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
      */
-    private <T extends CameraMetadata> List<Key<?>> getAvailableKeyList(Class<T> metadataClass) {
+    private <TKey> List<TKey>
+    getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass) {
 
         if (metadataClass.equals(CameraMetadata.class)) {
             throw new AssertionError(
@@ -128,7 +276,9 @@
                     "metadataClass must be a subclass of CameraMetadata");
         }
 
-        return Collections.unmodifiableList(getKeysStatic(metadataClass, /*instance*/null));
+        List<TKey> staticKeyList = CameraCharacteristics.<TKey>getKeysStatic(
+                metadataClass, keyClass, /*instance*/null);
+        return Collections.unmodifiableList(staticKeyList);
     }
 
     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
@@ -1346,19 +1496,6 @@
             new Key<Rational[]>("android.sensor.forwardMatrix2", Rational[].class);
 
     /**
-     * <p>Gain factor from electrons to raw units when
-     * ISO=100</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     * <p><b>Full capability</b> -
-     * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
-     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
-     *
-     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
-     */
-    public static final Key<Rational> SENSOR_BASE_GAIN_FACTOR =
-            new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
-
-    /**
      * <p>A fixed black level offset for each of the color filter arrangement
      * (CFA) mosaic channels.</p>
      * <p>This tag specifies the zero light value for each of the CFA mosaic
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 77640d1..6f5099b 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -766,14 +766,62 @@
         }
 
         /**
-         * This method is called when an image capture has completed and the
-         * result metadata is available.
+         * This method is called when an image capture makes partial forward progress; some
+         * (but not all) results from an image capture are available.
+         *
+         * <p>The result provided here will contain some subset of the fields of
+         * a full result. Multiple {@link #onCaptureProgressed} calls may happen per
+         * capture; a given result field will only be present in one partial
+         * capture at most. The final {@link #onCaptureCompleted} call will always
+         * contain all the fields (in particular, the union of all the fields of all
+         * the partial results composing the total result).</p>
+         *
+         * <p>For each request, some result data might be available earlier than others. The typical
+         * delay between each partial result (per request) is a single frame interval.
+         * For performance-oriented use-cases, applications should query the metadata they need
+         * to make forward progress from the partial results and avoid waiting for the completed
+         * result.</p>
+         *
+         * <p>Each request will generate at least {@code 1} partial results, and at most
+         * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p>
+         *
+         * <p>Depending on the request settings, the number of partial results per request
+         * will vary, although typically the partial count could be the same as long as the
+         * camera device subsystems enabled stay the same.</p>
          *
          * <p>The default implementation of this method does nothing.</p>
          *
          * @param camera The CameraDevice sending the callback.
          * @param request The request that was given to the CameraDevice
-         * @param result The output metadata from the capture, including the
+         * @param partialResult The partial output metadata from the capture, which
+         * includes a subset of the {@link TotalCaptureResult} fields.
+         *
+         * @see #capture
+         * @see #captureBurst
+         * @see #setRepeatingRequest
+         * @see #setRepeatingBurst
+         */
+        public void onCaptureProgressed(CameraDevice camera,
+                CaptureRequest request, CaptureResult partialResult) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called when an image capture has fully completed and all the
+         * result metadata is available.
+         *
+         * <p>This callback will always fire after the last {@link #onCaptureProgressed};
+         * in other words, no more partial results will be delivered once the completed result
+         * is available.</p>
+         *
+         * <p>For performance-intensive use-cases where latency is a factor, consider
+         * using {@link #onCaptureProgressed} instead.</p>
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param camera The CameraDevice sending the callback.
+         * @param request The request that was given to the CameraDevice
+         * @param result The total output metadata from the capture, including the
          * final capture parameters and the state of the camera system during
          * capture.
          *
@@ -783,7 +831,7 @@
          * @see #setRepeatingBurst
          */
         public void onCaptureCompleted(CameraDevice camera,
-                CaptureRequest request, CaptureResult result) {
+                CaptureRequest request, TotalCaptureResult result) {
             // default empty implementation
         }
 
@@ -796,6 +844,10 @@
          * the capture may have been pushed to their respective output
          * streams.</p>
          *
+         * <p>Some partial results may have been delivered before the capture fails;
+         * however after this callback fires, no more partial results will be delivered by
+         * {@link #onCaptureProgressed}.</p>
+         *
          * <p>The default implementation of this method does nothing.</p>
          *
          * @param camera
@@ -821,24 +873,57 @@
          * when a capture sequence finishes and all {@link CaptureResult}
          * or {@link CaptureFailure} for it have been returned via this listener.
          *
+         * <p>In total, there will be at least one result/failure returned by this listener
+         * before this callback is invoked. If the capture sequence is aborted before any
+         * requests have been processed, {@link #onCaptureSequenceAborted} is invoked instead.</p>
+         *
+         * <p>The default implementation does nothing.</p>
+         *
          * @param camera
          *            The CameraDevice sending the callback.
          * @param sequenceId
          *            A sequence ID returned by the {@link #capture} family of functions.
-         * @param lastFrameNumber
+         * @param frameNumber
          *            The last frame number (returned by {@link CaptureResult#getFrameNumber}
          *            or {@link CaptureFailure#getFrameNumber}) in the capture sequence.
-         *            The last frame number may be equal to NO_FRAMES_CAPTURED if no images
-         *            were captured for this sequence. This can happen, for example, when a
-         *            repeating request or burst is cleared right after being set.
          *
          * @see CaptureResult#getFrameNumber()
          * @see CaptureFailure#getFrameNumber()
          * @see CaptureResult#getSequenceId()
          * @see CaptureFailure#getSequenceId()
+         * @see #onCaptureSequenceAborted
          */
         public void onCaptureSequenceCompleted(CameraDevice camera,
-                int sequenceId, int lastFrameNumber) {
+                int sequenceId, long frameNumber) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called independently of the others in CaptureListener,
+         * when a capture sequence aborts before any {@link CaptureResult}
+         * or {@link CaptureFailure} for it have been returned via this listener.
+         *
+         * <p>Due to the asynchronous nature of the camera device, not all submitted captures
+         * are immediately processed. It is possible to clear out the pending requests
+         * by a variety of operations such as {@link CameraDevice#stopRepeating} or
+         * {@link CameraDevice#flush}. When such an event happens,
+         * {@link #onCaptureSequenceCompleted} will not be called.</p>
+         *
+         * <p>The default implementation does nothing.</p>
+         *
+         * @param camera
+         *            The CameraDevice sending the callback.
+         * @param sequenceId
+         *            A sequence ID returned by the {@link #capture} family of functions.
+         *
+         * @see CaptureResult#getFrameNumber()
+         * @see CaptureFailure#getFrameNumber()
+         * @see CaptureResult#getSequenceId()
+         * @see CaptureFailure#getSequenceId()
+         * @see #onCaptureSequenceCompleted
+         */
+        public void onCaptureSequenceAborted(CameraDevice camera,
+                int sequenceId) {
             // default empty implementation
         }
     }
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 03b342c..accceb1 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -84,9 +84,8 @@
         try {
             CameraBinderDecorator.throwOnError(
                     CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
-        } catch(CameraRuntimeException e) {
-            throw new IllegalStateException("Failed to setup camera vendor tags",
-                    e.asChecked());
+        } catch (CameraRuntimeException e) {
+            handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
         }
 
         try {
@@ -424,6 +423,18 @@
         return mDeviceIdList;
     }
 
+    private void handleRecoverableSetupErrors(CameraRuntimeException e, String msg) {
+        int problem = e.getReason();
+        switch (problem) {
+            case CameraAccessException.CAMERA_DISCONNECTED:
+                String errorMsg = CameraAccessException.getDefaultMessage(problem);
+                Log.w(TAG, msg + ": " + errorMsg);
+                break;
+            default:
+                throw new IllegalStateException(msg, e.asChecked());
+        }
+    }
+
     // TODO: this class needs unit tests
     // TODO: extract class into top level
     private class CameraServiceListener extends ICameraServiceListener.Stub {
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 5455189..4cde601 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -16,8 +16,7 @@
 
 package android.hardware.camera2;
 
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -36,7 +35,7 @@
  *
  * <p>
  * All instances of CameraMetadata are immutable. The list of keys with {@link #getKeys()}
- * never changes, nor do the values returned by any key with {@link #get} throughout
+ * never changes, nor do the values returned by any key with {@code #get} throughout
  * the lifetime of the object.
  * </p>
  *
@@ -44,7 +43,10 @@
  * @see CameraManager
  * @see CameraCharacteristics
  **/
-public abstract class CameraMetadata {
+public abstract class CameraMetadata<TKey> {
+
+    private static final String TAG = "CameraMetadataAb";
+    private static final boolean VERBOSE = false;
 
     /**
      * Set a camera metadata field to a value. The field definitions can be
@@ -74,8 +76,15 @@
      *
      * @param key The metadata field to read.
      * @return The value of that key, or {@code null} if the field is not set.
+     *
+     * @hide
      */
-    public abstract <T> T get(Key<T> key);
+     protected abstract <T> T getProtected(TKey key);
+
+     /**
+      * @hide
+      */
+     protected abstract Class<TKey> getKeyClass();
 
     /**
      * Returns a list of the keys contained in this map.
@@ -83,14 +92,16 @@
      * <p>The list returned is not modifiable, so any attempts to modify it will throw
      * a {@code UnsupportedOperationException}.</p>
      *
-     * <p>All values retrieved by a key from this list with {@link #get} are guaranteed to be
+     * <p>All values retrieved by a key from this list with {@code #get} are guaranteed to be
      * non-{@code null}. Each key is only listed once in the list. The order of the keys
      * is undefined.</p>
      *
      * @return List of the keys contained in this map.
      */
-    public List<Key<?>> getKeys() {
-        return Collections.unmodifiableList(getKeysStatic(this.getClass(), this));
+    @SuppressWarnings("unchecked")
+    public List<TKey> getKeys() {
+        Class<CameraMetadata<TKey>> thisClass = (Class<CameraMetadata<TKey>>) getClass();
+        return Collections.unmodifiableList(getKeysStatic(thisClass, getKeyClass(), this));
     }
 
     /**
@@ -101,24 +112,31 @@
      * Optionally, if {@code instance} is not null, then filter out any keys with null values.
      * </p>
      */
-    /*package*/ static ArrayList<Key<?>> getKeysStatic(Class<? extends CameraMetadata> type,
-            CameraMetadata instance) {
-        ArrayList<Key<?>> keyList = new ArrayList<Key<?>>();
+     /*package*/ @SuppressWarnings("unchecked")
+    static <TKey> ArrayList<TKey> getKeysStatic(
+             Class<?> type, Class<TKey> keyClass,
+             CameraMetadata<TKey> instance) {
+
+        if (VERBOSE) Log.v(TAG, "getKeysStatic for " + type);
+
+        ArrayList<TKey> keyList = new ArrayList<TKey>();
 
         Field[] fields = type.getDeclaredFields();
         for (Field field : fields) {
             // Filter for Keys that are public
-            if (field.getType().isAssignableFrom(Key.class) &&
+            if (field.getType().isAssignableFrom(keyClass) &&
                     (field.getModifiers() & Modifier.PUBLIC) != 0) {
-                Key<?> key;
+
+                TKey key;
                 try {
-                    key = (Key<?>) field.get(instance);
+                    key = (TKey) field.get(instance);
                 } catch (IllegalAccessException e) {
                     throw new AssertionError("Can't get IllegalAccessException", e);
                 } catch (IllegalArgumentException e) {
                     throw new AssertionError("Can't get IllegalArgumentException", e);
                 }
-                if (instance == null || instance.get(key) != null) {
+
+                if (instance == null || instance.getProtected(key) != null) {
                     keyList.add(key);
                 }
             }
@@ -127,113 +145,6 @@
         return keyList;
     }
 
-    // TODO: make final or abstract
-    public static class Key<T> {
-
-        private boolean mHasTag;
-        private int mTag;
-        private final Class<T> mType;
-        private final TypeReference<T> mTypeReference;
-        private final String mName;
-
-        /**
-         * @hide
-         */
-        public Key(String name, Class<T> type) {
-            if (name == null) {
-                throw new NullPointerException("Key needs a valid name");
-            } else if (type == null) {
-                throw new NullPointerException("Type needs to be non-null");
-            }
-            mName = name;
-            mType = type;
-            mTypeReference = TypeReference.createSpecializedTypeReference(type);
-        }
-
-        /**
-         * @hide
-         */
-        @SuppressWarnings("unchecked")
-        public Key(String name, TypeReference<T> typeReference) {
-            if (name == null) {
-                throw new NullPointerException("Key needs a valid name");
-            } else if (typeReference == null) {
-                throw new NullPointerException("TypeReference needs to be non-null");
-            }
-            mName = name;
-            mType = (Class<T>)typeReference.getRawType();
-            mTypeReference = typeReference;
-        }
-
-        public final String getName() {
-            return mName;
-        }
-
-        @Override
-        public final int hashCode() {
-            return mName.hashCode() ^ mTypeReference.hashCode();
-        }
-
-        @Override
-        public final boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-
-            if (!(o instanceof Key)) {
-                return false;
-            }
-
-            Key<?> lhs = (Key<?>)o;
-            return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
-        }
-
-        /**
-         * <p>
-         * Get the tag corresponding to this key. This enables insertion into the
-         * native metadata.
-         * </p>
-         *
-         * <p>This value is looked up the first time, and cached subsequently.</p>
-         *
-         * @return The tag numeric value corresponding to the string
-         *
-         * @hide
-         */
-        public final int getTag() {
-            if (!mHasTag) {
-                mTag = CameraMetadataNative.getTag(mName);
-                mHasTag = true;
-            }
-            return mTag;
-        }
-
-        /**
-         * Get the raw class backing the type {@code T} for this key.
-         *
-         * <p>The distinction is only important if {@code T} is a generic, e.g.
-         * {@code Range<Integer>} since the nested type will be erased.</p>
-         *
-         * @hide
-         */
-        public final Class<T> getType() {
-            // TODO: remove this; other places should use #getTypeReference() instead
-            return mType;
-        }
-
-        /**
-         * Get the type reference backing the type {@code T} for this key.
-         *
-         * <p>The distinction is only important if {@code T} is a generic, e.g.
-         * {@code Range<Integer>} since the nested type will be retained.</p>
-         *
-         * @hide
-         */
-        public final TypeReference<T> getTypeReference() {
-            return mTypeReference;
-        }
-    }
-
     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * The enum values below this point are generated from metadata
      * definitions in /system/media/camera/docs. Do not modify by hand or
@@ -336,7 +247,6 @@
      * <li>Manual sensitivity control<ul>
      * <li>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</li>
      * <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
-     * <li>{@link CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR android.sensor.baseGainFactor}</li>
      * </ul>
      * </li>
      * <li>Manual lens control<ul>
@@ -357,7 +267,6 @@
      * result.</p>
      *
      * @see CaptureRequest#BLACK_LEVEL_LOCK
-     * @see CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
      * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
@@ -1381,8 +1290,7 @@
 
     /**
      * <p>If the flash is available and charged, fire flash
-     * for this capture based on android.flash.firingPower and
-     * android.flash.firingTime.</p>
+     * for this capture.</p>
      * @see CaptureRequest#FLASH_MODE
      */
     public static final int FLASH_MODE_SINGLE = 1;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 8e0f2ae..a4aa296 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -16,7 +16,9 @@
 
 package android.hardware.camera2;
 
+import android.hardware.camera2.CameraCharacteristics.Key;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.TypeReference;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Rational;
@@ -25,6 +27,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Objects;
 
 
@@ -58,7 +61,98 @@
  * @see CameraDevice#setRepeatingRequest
  * @see CameraDevice#createCaptureRequest
  */
-public final class CaptureRequest extends CameraMetadata implements Parcelable {
+public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
+        implements Parcelable {
+
+    /**
+     * A {@code Key} is used to do capture request field lookups with
+     * {@link CaptureResult#get} or to set fields with
+     * {@link CaptureRequest.Builder#set(Key, Object)}.
+     *
+     * <p>For example, to set the crop rectangle for the next capture:
+     * <code><pre>
+     * Rect cropRectangle = new Rect(0, 0, 640, 480);
+     * captureRequestBuilder.set(SCALER_CROP_REGION, cropRectangle);
+     * </pre></code>
+     * </p>
+     *
+     * <p>To enumerate over all possible keys for {@link CaptureResult}, see
+     * {@link CameraCharacteristics#getAvailableCaptureResultKeys}.</p>
+     *
+     * @see CaptureResult#get
+     * @see CameraCharacteristics#getAvailableCaptureResultKeys
+     */
+    public final static class Key<T> {
+        private final CameraMetadataNative.Key<T> mKey;
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
+        public Key(String name, Class<T> type) {
+            mKey = new CameraMetadataNative.Key<T>(name, type);
+        }
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
+        public Key(String name, TypeReference<T> typeReference) {
+            mKey = new CameraMetadataNative.Key<T>(name, typeReference);
+        }
+
+        /**
+         * Return a camelCase, period separated name formatted like:
+         * {@code "root.section[.subsections].name"}.
+         *
+         * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
+         * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
+         *
+         * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
+         * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
+         * specific key might look like {@code "com.google.nexus.data.private"}.</p>
+         *
+         * @return String representation of the key name
+         */
+        public String getName() {
+            return mKey.getName();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public final int hashCode() {
+            return mKey.hashCode();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public final boolean equals(Object o) {
+            return o instanceof Key && ((Key<T>)o).mKey.equals(mKey);
+        }
+
+        /**
+         * Visible for CameraMetadataNative implementation only; do not use.
+         *
+         * TODO: Make this private or remove it altogether.
+         *
+         * @hide
+         */
+        public CameraMetadataNative.Key<T> getNativeKey() {
+            return mKey;
+        }
+
+        @SuppressWarnings({ "unchecked" })
+        /*package*/ Key(CameraMetadataNative.Key<?> nativeKey) {
+            mKey = (CameraMetadataNative.Key<T>) nativeKey;
+        }
+    }
 
     private final HashSet<Surface> mSurfaceSet;
     private final CameraMetadataNative mSettings;
@@ -93,17 +187,58 @@
      * Used by the Builder to create a mutable CaptureRequest.
      */
     private CaptureRequest(CameraMetadataNative settings) {
-        mSettings = settings;
+        mSettings = CameraMetadataNative.move(settings);
         mSurfaceSet = new HashSet<Surface>();
     }
 
-    @SuppressWarnings("unchecked")
-    @Override
+    /**
+     * Get a capture request field value.
+     *
+     * <p>The field definitions can be found in {@link CaptureRequest}.</p>
+     *
+     * <p>Querying the value for the same key more than once will return a value
+     * which is equal to the previous queried value.</p>
+     *
+     * @throws IllegalArgumentException if the key was not valid
+     *
+     * @param key The result field to read.
+     * @return The value of that key, or {@code null} if the field is not set.
+     */
     public <T> T get(Key<T> key) {
         return mSettings.get(key);
     }
 
     /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected <T> T getProtected(Key<?> key) {
+        return (T) mSettings.get(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class<Key<?>> getKeyClass() {
+        Object thisClass = Key.class;
+        return (Class<Key<?>>)thisClass;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Key<?>> getKeys() {
+        // Force the javadoc for this function to show up on the CaptureRequest page
+        return super.getKeys();
+    }
+
+    /**
      * Retrieve the tag for this request, if any.
      *
      * <p>This tag is not used for anything by the camera device, but can be
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index e0ddd57..9aa56cf 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -17,13 +17,16 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.params.Face;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
 import android.util.Rational;
 
+import java.util.List;
+
 /**
- * <p>The results of a single image capture from the image sensor.</p>
+ * <p>The subset of the results of a single image capture from the image sensor.</p>
  *
- * <p>Contains the final configuration for the capture hardware (sensor, lens,
+ * <p>Contains a subset of the final configuration for the capture hardware (sensor, lens,
  * flash), the processing pipeline, the control algorithms, and the output
  * buffers.</p>
  *
@@ -33,10 +36,106 @@
  * capture. The result also includes additional metadata about the state of the
  * camera device during the capture.</p>
  *
- * <p>{@link CameraCharacteristics} objects are immutable.</p>
+ * <p>Not all properties returned by {@link CameraCharacteristics#getAvailableCaptureResultKeys()}
+ * are necessarily available. Some results are {@link CaptureResult partial} and will
+ * not have every key set. Only {@link TotalCaptureResult total} results are guaranteed to have
+ * every key available that was enabled by the request.</p>
+ *
+ * <p>{@link CaptureResult} objects are immutable.</p>
  *
  */
-public final class CaptureResult extends CameraMetadata {
+public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
+
+    private static final String TAG = "CaptureResult";
+    private static final boolean VERBOSE = false;
+
+    /**
+     * A {@code Key} is used to do capture result field lookups with
+     * {@link CaptureResult#get}.
+     *
+     * <p>For example, to get the timestamp corresponding to the exposure of the first row:
+     * <code><pre>
+     * long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
+     * </pre></code>
+     * </p>
+     *
+     * <p>To enumerate over all possible keys for {@link CaptureResult}, see
+     * {@link CameraCharacteristics#getAvailableCaptureResultKeys}.</p>
+     *
+     * @see CaptureResult#get
+     * @see CameraCharacteristics#getAvailableCaptureResultKeys
+     */
+    public final static class Key<T> {
+        private final CameraMetadataNative.Key<T> mKey;
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
+        public Key(String name, Class<T> type) {
+            mKey = new CameraMetadataNative.Key<T>(name, type);
+        }
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
+        public Key(String name, TypeReference<T> typeReference) {
+            mKey = new CameraMetadataNative.Key<T>(name, typeReference);
+        }
+
+        /**
+         * Return a camelCase, period separated name formatted like:
+         * {@code "root.section[.subsections].name"}.
+         *
+         * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
+         * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
+         *
+         * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
+         * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
+         * specific key might look like {@code "com.google.nexus.data.private"}.</p>
+         *
+         * @return String representation of the key name
+         */
+        public String getName() {
+            return mKey.getName();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public final int hashCode() {
+            return mKey.hashCode();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public final boolean equals(Object o) {
+            return o instanceof Key && ((Key<T>)o).mKey.equals(mKey);
+        }
+
+        /**
+         * Visible for CameraMetadataNative implementation only; do not use.
+         *
+         * TODO: Make this private or remove it altogether.
+         *
+         * @hide
+         */
+        public CameraMetadataNative.Key<T> getNativeKey() {
+            return mKey;
+        }
+
+        @SuppressWarnings({ "unchecked" })
+        /*package*/ Key(CameraMetadataNative.Key<?> nativeKey) {
+            mKey = (CameraMetadataNative.Key<T>) nativeKey;
+        }
+    }
 
     private final CameraMetadataNative mResults;
     private final CaptureRequest mRequest;
@@ -55,7 +154,10 @@
             throw new IllegalArgumentException("parent was null");
         }
 
-        mResults = results;
+        mResults = CameraMetadataNative.move(results);
+        if (mResults.isEmpty()) {
+            throw new AssertionError("Results must not be empty");
+        }
         mRequest = parent;
         mSequenceId = sequenceId;
     }
@@ -68,26 +170,103 @@
         return new CameraMetadataNative(mResults);
     }
 
-    @Override
+    /**
+     * Creates a request-less result.
+     *
+     * <p><strong>For testing only.</strong></p>
+     * @hide
+     */
+    public CaptureResult(CameraMetadataNative results, int sequenceId) {
+        if (results == null) {
+            throw new IllegalArgumentException("results was null");
+        }
+
+        mResults = CameraMetadataNative.move(results);
+        if (mResults.isEmpty()) {
+            throw new AssertionError("Results must not be empty");
+        }
+
+        mRequest = null;
+        mSequenceId = sequenceId;
+    }
+
+    /**
+     * Get a capture result field value.
+     *
+     * <p>The field definitions can be found in {@link CaptureResult}.</p>
+     *
+     * <p>Querying the value for the same key more than once will return a value
+     * which is equal to the previous queried value.</p>
+     *
+     * @throws IllegalArgumentException if the key was not valid
+     *
+     * @param key The result field to read.
+     * @return The value of that key, or {@code null} if the field is not set.
+     */
     public <T> T get(Key<T> key) {
-        return mResults.get(key);
+        T value = mResults.get(key);
+        if (VERBOSE) Log.v(TAG, "#get for Key = " + key.getName() + ", returned value = " + value);
+        return value;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected <T> T getProtected(Key<?> key) {
+        return (T) mResults.get(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class<Key<?>> getKeyClass() {
+        Object thisClass = Key.class;
+        return (Class<Key<?>>)thisClass;
+    }
+
+    /**
+     * Dumps the native metadata contents to logcat.
+     *
+     * <p>Visibility for testing/debugging only. The results will not
+     * include any synthesized keys, as they are invisible to the native layer.</p>
+     *
+     * @hide
+     */
+    public void dumpToLog() {
+        mResults.dumpToLog();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Key<?>> getKeys() {
+        // Force the javadoc for this function to show up on the CaptureResult page
+        return super.getKeys();
     }
 
     /**
      * Get the request associated with this result.
      *
-     * <p>Whenever a request is successfully captured, with
-     * {@link CameraDevice.CaptureListener#onCaptureCompleted},
-     * the {@code result}'s {@code getRequest()} will return that {@code request}.
+     * <p>Whenever a request has been fully or partially captured, with
+     * {@link CameraDevice.CaptureListener#onCaptureCompleted} or
+     * {@link CameraDevice.CaptureListener#onCaptureProgressed}, the {@code result}'s
+     * {@code getRequest()} will return that {@code request}.
      * </p>
      *
-     * <p>In particular,
+     * <p>For example,
      * <code><pre>cameraDevice.capture(someRequest, new CaptureListener() {
      *     {@literal @}Override
      *     void onCaptureCompleted(CaptureRequest myRequest, CaptureResult myResult) {
      *         assert(myResult.getRequest.equals(myRequest) == true);
      *     }
-     * };
+     * }, null);
      * </code></pre>
      * </p>
      *
@@ -110,6 +289,7 @@
      * @return int frame number
      */
     public int getFrameNumber() {
+        // TODO: @hide REQUEST_FRAME_COUNT
         return get(REQUEST_FRAME_COUNT);
     }
 
@@ -123,6 +303,7 @@
      * @return int The ID for the sequence of requests that this capture result is a part of
      *
      * @see CameraDevice.CaptureListener#onCaptureSequenceCompleted
+     * @see CameraDevice.CaptureListener#onCaptureSequenceAborted
      */
     public int getSequenceId() {
         return mSequenceId;
@@ -1888,21 +2069,6 @@
             new Key<Long>("android.sensor.timestamp", long.class);
 
     /**
-     * <p>The temperature of the sensor, sampled at the time
-     * exposure began for this frame.</p>
-     * <p>The thermal diode being queried should be inside the sensor PCB, or
-     * somewhere close to it.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     * <p><b>Full capability</b> -
-     * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
-     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
-     *
-     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
-     */
-    public static final Key<Float> SENSOR_TEMPERATURE =
-            new Key<Float>("android.sensor.temperature", float.class);
-
-    /**
      * <p>The estimated camera neutral color in the native sensor colorspace at
      * the time of capture.</p>
      * <p>This value gives the neutral color point encoded as an RGB value in the
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
new file mode 100644
index 0000000..54568ed
--- /dev/null
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -0,0 +1,368 @@
+/*
+ * 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.hardware.camera2;
+
+import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.location.Location;
+import android.media.ExifInterface;
+import android.media.Image;
+import android.util.Size;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * The {@link DngCreator} class provides functions to write raw pixel data as a DNG file.
+ *
+ * <p>
+ * This class is designed to be used with the {@link android.graphics.ImageFormat#RAW_SENSOR}
+ * buffers available from {@link android.hardware.camera2.CameraDevice}, or with Bayer-type raw
+ * pixel data that is otherwise generated by an application.  The DNG metadata tags will be
+ * generated from a {@link android.hardware.camera2.CaptureResult} object or set directly.
+ * </p>
+ *
+ * <p>
+ * The DNG file format is a cross-platform file format that is used to store pixel data from
+ * camera sensors with minimal pre-processing applied.  DNG files allow for pixel data to be
+ * defined in a user-defined colorspace, and have associated metadata that allow for this
+ * pixel data to be converted to the standard CIE XYZ colorspace during post-processing.
+ * </p>
+ *
+ * <p>
+ * For more information on the DNG file format and associated metadata, please refer to the
+ * <a href=
+ * "https://wwwimages2.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf">
+ * Adobe DNG 1.4.0.0 specification</a>.
+ * </p>
+ */
+public final class DngCreator implements AutoCloseable {
+
+    /**
+     * Create a new DNG object.
+     *
+     * <p>
+     * It is not necessary to call any set methods to write a well-formatted DNG file.
+     * </p>
+     * <p>
+     * DNG metadata tags will be generated from the corresponding parameters in the
+     * {@link android.hardware.camera2.CaptureResult} object.  This removes or overrides
+     * all previous tags set.
+     * </p>
+     *
+     * @param characteristics an object containing the static
+     *          {@link android.hardware.camera2.CameraCharacteristics}.
+     * @param metadata a metadata object to generate tags from.
+     */
+    public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {
+        if (characteristics == null || metadata == null) {
+            throw new NullPointerException("Null argument to DngCreator constructor");
+        }
+        nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy());
+    }
+
+    /**
+     * Set the orientation value to write.
+     *
+     * <p>
+     * This will be written as the TIFF "Orientation" tag {@code (0x0112)}.
+     * Calling this will override any prior settings for this tag.
+     * </p>
+     *
+     * @param orientation the orientation value to set, one of:
+     *                    <ul>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_NORMAL}</li>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_HORIZONTAL}</li>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_180}</li>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_VERTICAL}</li>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_TRANSPOSE}</li>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_90}</li>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_TRANSVERSE}</li>
+     *                      <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_270}</li>
+     *                    </ul>
+     * @return this {@link #DngCreator} object.
+     */
+    public DngCreator setOrientation(int orientation) {
+
+        if (orientation < ExifInterface.ORIENTATION_UNDEFINED ||
+                orientation > ExifInterface.ORIENTATION_ROTATE_270) {
+            throw new IllegalArgumentException("Orientation " + orientation +
+                    " is not a valid EXIF orientation value");
+        }
+        nativeSetOrientation(orientation);
+        return this;
+    }
+
+    /**
+     * Set the thumbnail image.
+     *
+     * <p>
+     * Pixel data will be converted to a Baseline TIFF RGB image, with 8 bits per color channel.
+     * The alpha channel will be discarded.
+     * </p>
+     *
+     * <p>
+     * The given bitmap should not be altered while this object is in use.
+     * </p>
+     *
+     * @param pixels a {@link android.graphics.Bitmap} of pixel data.
+     * @return this {@link #DngCreator} object.
+     */
+    public DngCreator setThumbnail(Bitmap pixels) {
+        if (pixels == null) {
+            throw new NullPointerException("Null argument to setThumbnail");
+        }
+
+        Bitmap.Config config = pixels.getConfig();
+
+        if (config != Bitmap.Config.ARGB_8888) {
+            pixels = pixels.copy(Bitmap.Config.ARGB_8888, false);
+            if (pixels == null) {
+                throw new IllegalArgumentException("Unsupported Bitmap format " + config);
+            }
+            nativeSetThumbnailBitmap(pixels);
+        }
+
+        return this;
+    }
+
+    /**
+     * Set the thumbnail image.
+     *
+     * <p>
+     * Pixel data is interpreted as a {@link android.graphics.ImageFormat#YUV_420_888} image.
+     * </p>
+     *
+     * <p>
+     * The given image should not be altered while this object is in use.
+     * </p>
+     *
+     * @param pixels an {@link android.media.Image} object with the format
+     *               {@link android.graphics.ImageFormat#YUV_420_888}.
+     * @return this {@link #DngCreator} object.
+     */
+    public DngCreator setThumbnail(Image pixels) {
+        if (pixels == null) {
+            throw new NullPointerException("Null argument to setThumbnail");
+        }
+
+        int format = pixels.getFormat();
+        if (format != ImageFormat.YUV_420_888) {
+            throw new IllegalArgumentException("Unsupported image format " + format);
+        }
+
+        Image.Plane[] planes = pixels.getPlanes();
+        nativeSetThumbnailImage(pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
+                planes[0].getRowStride(), planes[0].getPixelStride(), planes[1].getBuffer(),
+                planes[1].getRowStride(), planes[1].getPixelStride(), planes[1].getBuffer(),
+                planes[1].getRowStride(), planes[1].getPixelStride());
+
+        return this;
+    }
+
+
+    /**
+     * Set image location metadata.
+     *
+     * <p>
+     * The given location object must contain at least a valid time, latitude, and longitude
+     * (equivalent to the values returned by {@link android.location.Location#getTime()},
+     * {@link android.location.Location#getLatitude()}, and
+     * {@link android.location.Location#getLongitude()} methods).
+     * </p>
+     *
+     * @param location an {@link android.location.Location} object to set.
+     * @return this {@link #DngCreator} object.
+     *
+     * @throws java.lang.IllegalArgumentException if the given location object doesn't
+     *          contain enough information to set location metadata.
+     */
+    public DngCreator setLocation(Location location) {
+        /*TODO*/
+        return this;
+    }
+
+    /**
+     * Set the user description string to write.
+     *
+     * <p>
+     * This is equivalent to setting the TIFF "ImageDescription" tag {@code (0x010E)}.
+     * </p>
+     *
+     * @param description the user description string.
+     * @return this {@link #DngCreator} object.
+     */
+    public DngCreator setDescription(String description) {
+        /*TODO*/
+        return this;
+    }
+
+    /**
+     * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
+     * the currently configured metadata.
+     *
+     * <p>
+     * Raw pixel data must have 16 bits per pixel, and the input must contain at least
+     * {@code offset + 2 * width * height)} bytes.  The width and height of
+     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
+     * and will typically be equal to the width and height of
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
+     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
+     * metadata is available to write a well-formatted DNG file, an
+     * {@link java.lang.IllegalStateException} will be thrown.
+     * </p>
+     *
+     * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+     * @param size the {@link Size} of the image to write, in pixels.
+     * @param pixels an {@link java.io.InputStream} of pixel data to write.
+     * @param offset the offset of the raw image in bytes.  This indicates how many bytes will
+     *               be skipped in the input before any pixel data is read.
+     *
+     * @throws IOException if an error was encountered in the input or output stream.
+     * @throws java.lang.IllegalStateException if not enough metadata information has been
+     *          set to write a well-formatted DNG file.
+     * @throws java.lang.IllegalArgumentException if the size passed in does not match the
+     */
+    public void writeInputStream(OutputStream dngOutput, Size size, InputStream pixels, long offset)
+            throws IOException {
+        if (dngOutput == null || pixels == null) {
+            throw new NullPointerException("Null argument to writeImage");
+        }
+        nativeWriteInputStream(dngOutput, pixels, offset);
+    }
+
+    /**
+     * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
+     * the currently configured metadata.
+     *
+     * <p>
+     * Raw pixel data must have 16 bits per pixel, and the input must contain at least
+     * {@code offset + 2 * width * height)} bytes.  The width and height of
+     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
+     * and will typically be equal to the width and height of
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
+     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
+     * metadata is available to write a well-formatted DNG file, an
+     * {@link java.lang.IllegalStateException} will be thrown.
+     * </p>
+     *
+     * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+     * @param size the {@link Size} of the image to write, in pixels.
+     * @param pixels an {@link java.nio.ByteBuffer} of pixel data to write.
+     * @param offset the offset of the raw image in bytes.  This indicates how many bytes will
+     *               be skipped in the input before any pixel data is read.
+     *
+     * @throws IOException if an error was encountered in the input or output stream.
+     * @throws java.lang.IllegalStateException if not enough metadata information has been
+     *          set to write a well-formatted DNG file.
+     */
+    public void writeByteBuffer(OutputStream dngOutput, Size size, ByteBuffer pixels, long offset)
+            throws IOException {
+        if (dngOutput == null || pixels == null) {
+            throw new NullPointerException("Null argument to writeImage");
+        }
+        nativeWriteByteBuffer(dngOutput, pixels, offset);
+    }
+
+    /**
+     * Write the pixel data to a DNG file with the currently configured metadata.
+     *
+     * <p>
+     * For this method to succeed, the {@link android.media.Image} input must contain
+     * {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data, otherwise an
+     * {@link java.lang.IllegalArgumentException} will be thrown.
+     * </p>
+     *
+     * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+     * @param pixels an {@link android.media.Image} to write.
+     *
+     * @throws java.io.IOException if an error was encountered in the output stream.
+     * @throws java.lang.IllegalArgumentException if an image with an unsupported format was used.
+     * @throws java.lang.IllegalStateException if not enough metadata information has been
+     *          set to write a well-formatted DNG file.
+     */
+    public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {
+        if (dngOutput == null || pixels == null) {
+            throw new NullPointerException("Null argument to writeImage");
+        }
+
+        int format = pixels.getFormat();
+        if (format != ImageFormat.RAW_SENSOR) {
+            throw new IllegalArgumentException("Unsupported image format " + format);
+        }
+
+        Image.Plane[] planes = pixels.getPlanes();
+        nativeWriteImage(dngOutput, pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
+                planes[0].getRowStride(), planes[0].getPixelStride());
+    }
+
+    @Override
+    public void close() {
+        nativeDestroy();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * This field is used by native code, do not access or modify.
+     */
+    private long mNativeContext;
+
+    private static native void nativeClassInit();
+
+    private synchronized native void nativeInit(CameraMetadataNative nativeCharacteristics,
+                                                CameraMetadataNative nativeResult);
+
+    private synchronized native void nativeDestroy();
+
+    private synchronized native void nativeSetOrientation(int orientation);
+
+    private synchronized native void nativeSetThumbnailBitmap(Bitmap bitmap);
+
+    private synchronized native void nativeSetThumbnailImage(int width, int height,
+                                                             ByteBuffer yBuffer, int yRowStride,
+                                                             int yPixStride, ByteBuffer uBuffer,
+                                                             int uRowStride, int uPixStride,
+                                                             ByteBuffer vBuffer, int vRowStride,
+                                                             int vPixStride);
+
+    private synchronized native void nativeWriteImage(OutputStream out, int width, int height,
+                                                      ByteBuffer rawBuffer, int rowStride,
+                                                      int pixStride) throws IOException;
+
+    private synchronized native void nativeWriteByteBuffer(OutputStream out, ByteBuffer rawBuffer,
+                                                           long offset) throws IOException;
+
+    private synchronized native void nativeWriteInputStream(OutputStream out, InputStream rawStream,
+                                                            long offset) throws IOException;
+
+    static {
+        nativeClassInit();
+    }
+}
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
new file mode 100644
index 0000000..2647959
--- /dev/null
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.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 android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>The total assembled results of a single image capture from the image sensor.</p>
+ *
+ * <p>Contains the final configuration for the capture hardware (sensor, lens,
+ * flash), the processing pipeline, the control algorithms, and the output
+ * buffers.</p>
+ *
+ * <p>A {@code TotalCaptureResult} is produced by a {@link CameraDevice} after processing a
+ * {@link CaptureRequest}. All properties listed for capture requests can also
+ * be queried on the capture result, to determine the final values used for
+ * capture. The result also includes additional metadata about the state of the
+ * camera device during the capture.</p>
+ *
+ * <p>All properties returned by {@link CameraCharacteristics#getAvailableCaptureResultKeys()}
+ * are available (that is {@link CaptureResult#get} will return non-{@code null}, if and only if
+ * that key that was enabled by the request. A few keys such as
+ * {@link CaptureResult#STATISTICS_FACES} are disabled by default unless enabled with a switch (such
+ * as {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE}). Refer to each key documentation on
+ * a case-by-case basis.</p>
+ *
+ * <p>{@link TotalCaptureResult} objects are immutable.</p>
+ *
+ * @see CameraDevice.CaptureListener#onCaptureCompleted
+ */
+public final class TotalCaptureResult extends CaptureResult {
+
+    /**
+     * Takes ownership of the passed-in properties object
+     * @hide
+     */
+    public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent, int sequenceId) {
+        super(results, parent, sequenceId);
+    }
+
+    /**
+     * Creates a request-less result.
+     *
+     * <p><strong>For testing only.</strong></p>
+     * @hide
+     */
+    public TotalCaptureResult(CameraMetadataNative results, int sequenceId) {
+        super(results, sequenceId);
+    }
+
+    /**
+     * Get the read-only list of partial results that compose this total result.
+     *
+     * <p>The list is returned is unmodifiable; attempting to modify it will result in a
+     * {@code UnsupportedOperationException} being thrown.</p>
+     *
+     * <p>The list size will be inclusive between {@code 1} and
+     * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}, in ascending order
+     * of when {@link CameraDevice.CaptureListener#onCaptureProgressed} was invoked.</p>
+     *
+     * @return unmodifiable list of partial results
+     */
+    public List<CaptureResult> getPartialResults() {
+        // TODO
+        return Collections.unmodifiableList(null);
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index b082a70..7b24976 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -24,6 +24,7 @@
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.hardware.camera2.utils.LongParcelable;
@@ -359,7 +360,7 @@
                             holder.getListener().onCaptureSequenceCompleted(
                                     CameraDevice.this,
                                     requestId,
-                                    (int)lastFrameNumber);
+                                    lastFrameNumber);
                         }
                     }
                 };
@@ -717,7 +718,7 @@
                                 holder.getListener().onCaptureSequenceCompleted(
                                     CameraDevice.this,
                                     requestId,
-                                    (int)lastFrameNumber);
+                                    lastFrameNumber);
                             }
                         }
                     };
@@ -888,12 +889,15 @@
             }
 
             final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
-            final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
+
 
             Runnable resultDispatch = null;
 
             // Either send a partial result or the final capture completed result
             if (quirkIsPartialResult) {
+                final CaptureResult resultAsCapture =
+                        new CaptureResult(result, request, requestId);
+
                 // Partial result
                 resultDispatch = new Runnable() {
                     @Override
@@ -907,6 +911,9 @@
                     }
                 };
             } else {
+                final TotalCaptureResult resultAsCapture =
+                        new TotalCaptureResult(result, request, requestId);
+
                 // Final capture result
                 resultDispatch = new Runnable() {
                     @Override
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 27cfd38..ab2c49a 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -20,7 +20,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
@@ -46,10 +46,14 @@
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.utils.TypeReference;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -58,7 +62,147 @@
  * Implementation of camera metadata marshal/unmarshal across Binder to
  * the camera service
  */
-public class CameraMetadataNative extends CameraMetadata implements Parcelable {
+public class CameraMetadataNative implements Parcelable {
+
+    public static class Key<T> {
+        private boolean mHasTag;
+        private int mTag;
+        private final Class<T> mType;
+        private final TypeReference<T> mTypeReference;
+        private final String mName;
+
+        /**
+         * Visible for testing only.
+         *
+         * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
+         * for application code or vendor-extended keys.</p>
+         */
+        public Key(String name, Class<T> type) {
+            if (name == null) {
+                throw new NullPointerException("Key needs a valid name");
+            } else if (type == null) {
+                throw new NullPointerException("Type needs to be non-null");
+            }
+            mName = name;
+            mType = type;
+            mTypeReference = TypeReference.createSpecializedTypeReference(type);
+        }
+
+        /**
+         * Visible for testing only.
+         *
+         * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
+         * for application code or vendor-extended keys.</p>
+         */
+        @SuppressWarnings("unchecked")
+        public Key(String name, TypeReference<T> typeReference) {
+            if (name == null) {
+                throw new NullPointerException("Key needs a valid name");
+            } else if (typeReference == null) {
+                throw new NullPointerException("TypeReference needs to be non-null");
+            }
+            mName = name;
+            mType = (Class<T>)typeReference.getRawType();
+            mTypeReference = typeReference;
+        }
+
+        /**
+         * Return a camelCase, period separated name formatted like:
+         * {@code "root.section[.subsections].name"}.
+         *
+         * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
+         * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
+         *
+         * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
+         * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
+         * specific key might look like {@code "com.google.nexus.data.private"}.</p>
+         *
+         * @return String representation of the key name
+         */
+        public final String getName() {
+            return mName;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public final int hashCode() {
+            return mName.hashCode() ^ mTypeReference.hashCode();
+        }
+
+        /**
+         * Compare this key against other native keys, request keys, result keys, and
+         * characteristics keys.
+         *
+         * <p>Two keys are considered equal if their name and type reference are equal.</p>
+         *
+         * <p>Note that the equality against non-native keys is one-way. A native key may be equal
+         * to a result key; but that same result key will not be equal to a native key.</p>
+         */
+        @SuppressWarnings("rawtypes")
+        @Override
+        public final boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+
+            Key<?> lhs;
+
+            if (o instanceof CaptureResult.Key) {
+                lhs = ((CaptureResult.Key)o).getNativeKey();
+            } else if (o instanceof CaptureRequest.Key) {
+                lhs = ((CaptureRequest.Key)o).getNativeKey();
+            } else if (o instanceof CameraCharacteristics.Key) {
+                lhs = ((CameraCharacteristics.Key)o).getNativeKey();
+            } else if ((o instanceof Key)) {
+                lhs = (Key<?>)o;
+            } else {
+                return false;
+            }
+
+            return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
+        }
+
+        /**
+         * <p>
+         * Get the tag corresponding to this key. This enables insertion into the
+         * native metadata.
+         * </p>
+         *
+         * <p>This value is looked up the first time, and cached subsequently.</p>
+         *
+         * @return The tag numeric value corresponding to the string
+         */
+        public final int getTag() {
+            if (!mHasTag) {
+                mTag = CameraMetadataNative.getTag(mName);
+                mHasTag = true;
+            }
+            return mTag;
+        }
+
+        /**
+         * Get the raw class backing the type {@code T} for this key.
+         *
+         * <p>The distinction is only important if {@code T} is a generic, e.g.
+         * {@code Range<Integer>} since the nested type will be erased.</p>
+         */
+        public final Class<T> getType() {
+            // TODO: remove this; other places should use #getTypeReference() instead
+            return mType;
+        }
+
+        /**
+         * Get the type reference backing the type {@code T} for this key.
+         *
+         * <p>The distinction is only important if {@code T} is a generic, e.g.
+         * {@code Range<Integer>} since the nested type will be retained.</p>
+         */
+        public final TypeReference<T> getTypeReference() {
+            return mTypeReference;
+        }
+    }
 
     private static final String TAG = "CameraMetadataJV";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -84,6 +228,20 @@
         }
     }
 
+    /**
+     * Move the contents from {@code other} into a new camera metadata instance.</p>
+     *
+     * <p>After this call, {@code other} will become empty.</p>
+     *
+     * @param other the previous metadata instance which will get pilfered
+     * @return a new metadata instance with the values from {@code other} moved into it
+     */
+    public static CameraMetadataNative move(CameraMetadataNative other) {
+        CameraMetadataNative newObject = new CameraMetadataNative();
+        newObject.swap(other);
+        return newObject;
+    }
+
     public static final Parcelable.Creator<CameraMetadataNative> CREATOR =
             new Parcelable.Creator<CameraMetadataNative>() {
         @Override
@@ -109,8 +267,36 @@
         nativeWriteToParcel(dest);
     }
 
-    @Override
+    /**
+     * @hide
+     */
+    public <T> T get(CameraCharacteristics.Key<T> key) {
+        return get(key.getNativeKey());
+    }
+
+    /**
+     * @hide
+     */
+    public <T> T get(CaptureResult.Key<T> key) {
+        return get(key.getNativeKey());
+    }
+
+    /**
+     * @hide
+     */
+    public <T> T get(CaptureRequest.Key<T> key) {
+        return get(key.getNativeKey());
+    }
+
+    /**
+     * Look-up a metadata field value by its key.
+     *
+     * @param key a non-{@code null} key instance
+     * @return the field corresponding to the {@code key}, or {@code null} if no value was set
+     */
     public <T> T get(Key<T> key) {
+        Preconditions.checkNotNull(key, "key must not be null");
+
         T value = getOverride(key);
         if (value != null) {
             return value;
@@ -152,6 +338,18 @@
         setBase(key, value);
     }
 
+    public <T> void set(CaptureRequest.Key<T> key, T value) {
+        set(key.getNativeKey(), value);
+    }
+
+    public <T> void set(CaptureResult.Key<T> key, T value) {
+        set(key.getNativeKey(), value);
+    }
+
+    public <T> void set(CameraCharacteristics.Key<T> key, T value) {
+        set(key.getNativeKey(), value);
+    }
+
     // Keep up-to-date with camera_metadata.h
     /**
      * @hide
@@ -188,6 +386,18 @@
         mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
     }
 
+    private <T> T getBase(CameraCharacteristics.Key<T> key) {
+        return getBase(key.getNativeKey());
+    }
+
+    private <T> T getBase(CaptureResult.Key<T> key) {
+        return getBase(key.getNativeKey());
+    }
+
+    private <T> T getBase(CaptureRequest.Key<T> key) {
+        return getBase(key.getNativeKey());
+    }
+
     private <T> T getBase(Key<T> key) {
         int tag = key.getTag();
         byte[] values = readValues(tag);
@@ -342,6 +552,18 @@
         return new StreamConfigurationMap(configurations, minFrameDurations, stallDurations);
     }
 
+    private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
+        setBase(key.getNativeKey(), value);
+    }
+
+    private <T> void setBase(CaptureResult.Key<T> key, T value) {
+        setBase(key.getNativeKey(), value);
+    }
+
+    private <T> void setBase(CaptureRequest.Key<T> key, T value) {
+        setBase(key.getNativeKey(), value);
+    }
+
     private <T> void setBase(Key<T> key, T value) {
         int tag = key.getTag();
 
@@ -440,6 +662,7 @@
 
     private native synchronized byte[] nativeReadValues(int tag);
     private native synchronized void nativeWriteValues(int tag, byte[] src);
+    private native synchronized void nativeDump() throws IOException; // dump to ALOGD
 
     private static native int nativeGetTagFromKey(String keyName)
             throws IllegalArgumentException;
@@ -531,6 +754,22 @@
         return nativeReadValues(tag);
     }
 
+    /**
+     * Dumps the native metadata contents to logcat.
+     *
+     * <p>Visibility for testing/debugging only. The results will not
+     * include any synthesized keys, as they are invisible to the native layer.</p>
+     *
+     * @hide
+     */
+    public void dumpToLog() {
+        try {
+            nativeDump();
+        } catch (IOException e) {
+            Log.wtf(TAG, "Dump logging failed", e);
+        }
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -599,5 +838,4 @@
         nativeClassInit();
         registerAllMarshalers();
     }
-
 }
diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.java b/core/java/android/hardware/hdmi/HdmiCecMessage.java
index ddaf870..62fa279 100644
--- a/core/java/android/hardware/hdmi/HdmiCecMessage.java
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.java
@@ -46,7 +46,7 @@
     public HdmiCecMessage(int source, int destination, int opcode, byte[] params) {
         mSource = source;
         mDestination = destination;
-        mOpcode = opcode;
+        mOpcode = opcode & 0xFF;
         mParams = Arrays.copyOf(params, params.length);
     }
 
@@ -123,6 +123,7 @@
          * @param p HdmiCecMessage object to read the Rating from
          * @return a new HdmiCecMessage created from the data in the parcel
          */
+        @Override
         public HdmiCecMessage createFromParcel(Parcel p) {
             int source = p.readInt();
             int destination = p.readInt();
@@ -131,6 +132,7 @@
             p.readByteArray(params);
             return new HdmiCecMessage(source, destination, opcode, params);
         }
+        @Override
         public HdmiCecMessage[] newArray(int size) {
             return new HdmiCecMessage[size];
         }
@@ -139,11 +141,40 @@
     @Override
     public String toString() {
         StringBuffer s = new StringBuffer();
-        s.append(String.format("src: %d dst: %d op: %2X params: ", mSource, mDestination, mOpcode));
-        for (byte data : mParams) {
-            s.append(String.format("%02X ", data));
+        s.append(String.format("<%s> src: %d, dst: %d",
+                opcodeToString(mOpcode), mSource, mDestination));
+        if (mParams.length > 0) {
+            s.append(", params:");
+            for (byte data : mParams) {
+                s.append(String.format(" %02X", data));
+            }
         }
         return s.toString();
     }
+
+    private static String opcodeToString(int opcode) {
+        switch (opcode) {
+            case HdmiCec.MESSAGE_FEATURE_ABORT:
+                return "Feature Abort";
+            case HdmiCec.MESSAGE_CEC_VERSION:
+                return "CEC Version";
+            case HdmiCec.MESSAGE_REQUEST_ARC_INITIATION:
+                return "Request ARC Initiation";
+            case HdmiCec.MESSAGE_REQUEST_ARC_TERMINATION:
+                return "Request ARC Termination";
+            case HdmiCec.MESSAGE_REPORT_ARC_INITIATED:
+                return "Report ARC Initiated";
+            case HdmiCec.MESSAGE_REPORT_ARC_TERMINATED:
+                return "Report ARC Terminated";
+            case HdmiCec.MESSAGE_TEXT_VIEW_ON:
+                return "Text View On";
+            case HdmiCec.MESSAGE_ACTIVE_SOURCE:
+                return "Active Source";
+            case HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS:
+                return "Give Device Power Status";
+            default:
+                return String.format("Opcode: %02X", opcode);
+        }
+    }
 }
 
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index e489e05..64516e6 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -94,11 +94,26 @@
             mNetId = netId;
         }
 
+        private void connectToHost(Socket socket, String host, int port) throws IOException {
+            // Lookup addresses only on this Network.
+            InetAddress[] hostAddresses = getAllByName(host);
+            // Try all but last address ignoring exceptions.
+            for (int i = 0; i < hostAddresses.length - 1; i++) {
+                try {
+                    socket.connect(new InetSocketAddress(hostAddresses[i], port));
+                    return;
+                } catch (IOException e) {
+                }
+            }
+            // Try last address.  Do throw exceptions.
+            socket.connect(new InetSocketAddress(hostAddresses[hostAddresses.length - 1], port));
+        }
+
         @Override
         public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
             Socket socket = createSocket();
             socket.bind(new InetSocketAddress(localHost, localPort));
-            socket.connect(new InetSocketAddress(host, port));
+            connectToHost(socket, host, port);
             return socket;
         }
 
@@ -121,7 +136,7 @@
         @Override
         public Socket createSocket(String host, int port) throws IOException {
             Socket socket = createSocket();
-            socket.connect(new InetSocketAddress(host, port));
+            connectToHost(socket, host, port);
             return socket;
         }
 
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index c2b06a2..1c18ba5 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -257,31 +257,43 @@
     }
 
     /**
-     * called to go through our list of requests and see if we're
-     * good enough to try connecting.
+     * Called to go through our list of requests and see if we're
+     * good enough to try connecting, or if we have gotten worse and
+     * need to disconnect.
      *
-     * Only does connects - we disconnect when requested via
+     * Once we are registered, does nothing: we disconnect when requested via
      * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection
      * between modules (bearer or ConnectivityService dies) or more commonly
      * when the NetworkInfo reports to ConnectivityService it is disconnected.
      */
     private void evalScores() {
-        if (mConnectionRequested) {
-            if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size());
-            // already trying
-            return;
-        }
-        if (VDBG) log("evalScores!");
-        for (int i=0; i < mNetworkRequests.size(); i++) {
-            int score = mNetworkRequests.valueAt(i).score;
-            if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
-            if (score < mNetworkScore) {
-                // have a request that has a lower scored network servicing it
-                // (or no network) than we could provide, so lets connect!
-                mConnectionRequested = true;
-                connect();
+        synchronized(mLockObj) {
+            if (mRegistered) {
+                if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size());
+                // already trying
                 return;
             }
+            if (VDBG) log("evalScores!");
+            for (int i=0; i < mNetworkRequests.size(); i++) {
+                int score = mNetworkRequests.valueAt(i).score;
+                if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
+                if (score < mNetworkScore) {
+                    // have a request that has a lower scored network servicing it
+                    // (or no network) than we could provide, so let's connect!
+                    mConnectionRequested = true;
+                    connect();
+                    return;
+                }
+            }
+            // Our score is not high enough to satisfy any current request.
+            // This can happen if our score goes down after a connection is
+            // requested but before we actually connect. In this case, disconnect
+            // rather than continue trying - there's no point connecting if we know
+            // we'll just be torn down as soon as we do.
+            if (mConnectionRequested) {
+                mConnectionRequested = false;
+                disconnect();
+            }
         }
     }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index af45fa0..bc57b33 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2443,8 +2443,10 @@
             pw.print(prefix); pw.print("    Capacity: ");
                     printmAh(pw, helper.getPowerProfile().getBatteryCapacity());
                     pw.print(", Computed drain: "); printmAh(pw, helper.getComputedPower());
-                    pw.print(", Min drain: "); printmAh(pw, helper.getMinDrainedPower());
-                    pw.print(", Max drain: "); printmAh(pw, helper.getMaxDrainedPower());
+                    pw.print(", actual drain: "); printmAh(pw, helper.getMinDrainedPower());
+                    if (helper.getMinDrainedPower() != helper.getMaxDrainedPower()) {
+                        pw.print("-"); printmAh(pw, helper.getMaxDrainedPower());
+                    }
                     pw.println();
             for (int i=0; i<sippers.size(); i++) {
                 BatterySipper bs = sippers.get(i);
@@ -3301,7 +3303,8 @@
             if (rec.time >= histStart) {
                 if (histStart >= 0 && !printed) {
                     if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
-                            || rec.cmd == HistoryItem.CMD_RESET) {
+                            || rec.cmd == HistoryItem.CMD_RESET
+                            || rec.cmd == HistoryItem.CMD_START) {
                         printed = true;
                         hprinter.printNextItem(pw, rec, baseTime, checkin,
                                 (flags&DUMP_VERBOSE) != 0);
@@ -3351,7 +3354,10 @@
                 }
                 hprinter.printNextItem(pw, rec, baseTime, checkin,
                         (flags&DUMP_VERBOSE) != 0);
-            } else if (rec.eventCode != HistoryItem.EVENT_NONE) {
+            } else if (false && rec.eventCode != HistoryItem.EVENT_NONE) {
+                // This is an attempt to aggregate the previous state and generate
+                // fake events to reflect that state at the point where we start
+                // printing real events.  It doesn't really work right, so is turned off.
                 if (tracker == null) {
                     tracker = new HistoryEventTracker();
                 }
diff --git a/core/java/android/os/CommonBundle.java b/core/java/android/os/CommonBundle.java
index e11f170..c1b202c 100644
--- a/core/java/android/os/CommonBundle.java
+++ b/core/java/android/os/CommonBundle.java
@@ -18,11 +18,10 @@
 
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.SparseArray;
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -304,6 +303,16 @@
     }
 
     /**
+     * Inserts all mappings from the given Map into this CommonBundle.
+     *
+     * @param map a Map
+     */
+    void putAll(Map map) {
+        unparcel();
+        mMap.putAll(map);
+    }
+
+    /**
      * Returns a Set containing the Strings used as keys in this Bundle.
      *
      * @return a Set of String keys
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index c2cd3be..cd8d515 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -17,7 +17,14 @@
 package android.os;
 
 import android.util.ArrayMap;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -25,7 +32,8 @@
  * restored.
  *
  */
-public final class PersistableBundle extends CommonBundle {
+public final class PersistableBundle extends CommonBundle implements XmlUtils.WriteMapCallback {
+    private static final String TAG_PERSISTABLEMAP = "pbundle_as_map";
     public static final PersistableBundle EMPTY;
     static final Parcel EMPTY_PARCEL;
 
@@ -88,6 +96,38 @@
     }
 
     /**
+     * Constructs a PersistableBundle containing the mappings passed in.
+     *
+     * @param map a Map containing only those items that can be persisted.
+     * @throws IllegalArgumentException if any element of #map cannot be persisted.
+     */
+    private PersistableBundle(Map<String, Object> map) {
+        super();
+
+        // First stuff everything in.
+        putAll(map);
+
+        // Now verify each item throwing an exception if there is a violation.
+        Set<String> keys = map.keySet();
+        Iterator<String> iterator = keys.iterator();
+        while (iterator.hasNext()) {
+            String key = iterator.next();
+            Object value = map.get(key);
+            if (value instanceof Map) {
+                // Fix up any Maps by replacing them with PersistableBundles.
+                putPersistableBundle(key, new PersistableBundle((Map<String, Object>) value));
+            } else if (!(value instanceof Integer) && !(value instanceof Long) &&
+                    !(value instanceof Double) && !(value instanceof String) &&
+                    !(value instanceof int[]) && !(value instanceof long[]) &&
+                    !(value instanceof double[]) && !(value instanceof String[]) &&
+                    !(value instanceof PersistableBundle) && (value != null)) {
+                throw new IllegalArgumentException("Bad value in PersistableBundle key=" + key +
+                        " value=" + value);
+            }
+        }
+    }
+
+    /**
      * Make a PersistableBundle for a single key/value pair.
      *
      * @hide
@@ -206,6 +246,7 @@
      *
      * @param bundle a PersistableBundle
      */
+    @Override
     public void putAll(PersistableBundle bundle) {
         super.putAll(bundle);
     }
@@ -323,6 +364,7 @@
      * @param key a String, or null
      * @param value a Bundle object, or null
      */
+    @Override
     public void putPersistableBundle(String key, PersistableBundle value) {
         super.putPersistableBundle(key, value);
     }
@@ -539,6 +581,57 @@
         super.readFromParcelInner(parcel);
     }
 
+    /** @hide */
+    @Override
+    public void writeUnknownObject(Object v, String name, XmlSerializer out)
+            throws XmlPullParserException, IOException {
+        if (v instanceof PersistableBundle) {
+            out.startTag(null, TAG_PERSISTABLEMAP);
+            out.attribute(null, "name", name);
+            ((PersistableBundle) v).saveToXml(out);
+            out.endTag(null, TAG_PERSISTABLEMAP);
+        } else {
+            throw new XmlPullParserException("Unknown Object o=" + v);
+        }
+    }
+
+    /** @hide */
+    public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+        unparcel();
+        XmlUtils.writeMapXml(mMap, out, this);
+    }
+
+    /** @hide */
+    static class MyReadMapCallback implements  XmlUtils.ReadMapCallback {
+        @Override
+        public Object readThisUnknownObjectXml(XmlPullParser in, String tag)
+                throws XmlPullParserException, IOException {
+            if (TAG_PERSISTABLEMAP.equals(tag)) {
+                return restoreFromXml(in);
+            }
+            throw new XmlPullParserException("Unknown tag=" + tag);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException,
+            XmlPullParserException {
+        final int outerDepth = in.getDepth();
+        final String startTag = in.getName();
+        final String[] tagName = new String[1];
+        int event;
+        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
+                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
+            if (event == XmlPullParser.START_TAG) {
+                return new PersistableBundle((Map<String, Object>)
+                        XmlUtils.readThisMapXml(in, startTag, tagName, new MyReadMapCallback()));
+            }
+        }
+        return EMPTY;
+    }
+
     @Override
     synchronized public String toString() {
         if (mParcelledData != null) {
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index d2d6ade..5e005d0 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -37,20 +37,22 @@
  * @hide
  */
 public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
+    private static final String TAG = "SeekBarVolumizer";
 
     public interface Callback {
         void onSampleStarting(SeekBarVolumizer sbv);
     }
 
-    private Context mContext;
-    private Handler mHandler;
+    private final Context mContext;
+    private final Handler mHandler;
     private final Callback mCallback;
+    private final Uri mDefaultUri;
+    private final AudioManager mAudioManager;
+    private final int mStreamType;
+    private final int mMaxStreamVolume;
 
-    private AudioManager mAudioManager;
-    private int mStreamType;
     private int mOriginalStreamVolume;
     private Ringtone mRingtone;
-
     private int mLastProgress = -1;
     private SeekBar mSeekBar;
     private int mVolumeBeforeMute = -1;
@@ -58,9 +60,10 @@
     private static final int MSG_SET_STREAM_VOLUME = 0;
     private static final int MSG_START_SAMPLE = 1;
     private static final int MSG_STOP_SAMPLE = 2;
+    private static final int MSG_INIT_SAMPLE = 3;
     private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
 
-    private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
+    private ContentObserver mVolumeObserver = new ContentObserver(new Handler()) {
         @Override
         public void onChange(boolean selfChange) {
             super.onChange(selfChange);
@@ -71,27 +74,17 @@
         }
     };
 
-    public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType, Uri defaultUri,
+    public SeekBarVolumizer(Context context, int streamType, Uri defaultUri,
             Callback callback) {
         mContext = context;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mStreamType = streamType;
-        mSeekBar = seekBar;
-
-        HandlerThread thread = new HandlerThread(VolumePreference.TAG + ".CallbackHandler");
+        mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
+        HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
         thread.start();
         mHandler = new Handler(thread.getLooper(), this);
         mCallback = callback;
-
-        initSeekBar(seekBar, defaultUri);
-    }
-
-    private void initSeekBar(SeekBar seekBar, Uri defaultUri) {
-        seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
         mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
-        seekBar.setProgress(mOriginalStreamVolume);
-        seekBar.setOnSeekBarChangeListener(this);
-
         mContext.getContentResolver().registerContentObserver(
                 System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
                 false, mVolumeObserver);
@@ -105,12 +98,16 @@
                 defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
             }
         }
+        mDefaultUri = defaultUri;
+        mHandler.sendEmptyMessage(MSG_INIT_SAMPLE);
+    }
 
-        mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
-
-        if (mRingtone != null) {
-            mRingtone.setStreamType(mStreamType);
-        }
+    public void setSeekBar(SeekBar seekBar) {
+        mSeekBar = seekBar;
+        mSeekBar.setOnSeekBarChangeListener(null);
+        mSeekBar.setMax(mMaxStreamVolume);
+        mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume);
+        mSeekBar.setOnSeekBarChangeListener(this);
     }
 
     @Override
@@ -125,12 +122,22 @@
             case MSG_STOP_SAMPLE:
                 onStopSample();
                 break;
+            case MSG_INIT_SAMPLE:
+                onInitSample();
+                break;
             default:
-                Log.e(VolumePreference.TAG, "invalid SeekBarVolumizer message: "+msg.what);
+                Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
         }
         return true;
     }
 
+    private void onInitSample() {
+        mRingtone = RingtoneManager.getRingtone(mContext, mDefaultUri);
+        if (mRingtone != null) {
+            mRingtone.setStreamType(mStreamType);
+        }
+    }
+
     private void postStartSample() {
         mHandler.removeMessages(MSG_START_SAMPLE);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 171e5c3..df9e10e 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -66,7 +66,8 @@
         super.onBindDialogView(view);
 
         final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
-        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType, null, this);
+        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), mStreamType, null, this);
+        mSeekBarVolumizer.setSeekBar(seekBar);
 
         getPreferenceManager().registerOnActivityStopListener(this);
 
diff --git a/core/java/android/tv/ITvInputHardware.aidl b/core/java/android/tv/ITvInputHardware.aidl
new file mode 100644
index 0000000..7250453
--- /dev/null
+++ b/core/java/android/tv/ITvInputHardware.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.tv;
+
+import android.tv.TvStreamConfig;
+import android.view.KeyEvent;
+import android.view.Surface;
+
+/**
+ * TvInputService representing a physical port should connect to HAL through this interface.
+ * Framework will take care of communication among system services including TvInputManagerService,
+ * HdmiControlService, AudioService, etc.
+ *
+ * @hide
+ */
+interface ITvInputHardware {
+    /**
+     * Make the input render on the surface according to the config. In case of HDMI, this will
+     * trigger CEC commands for adjusting active HDMI source. Returns true on success.
+     */
+    boolean setSurface(in Surface surface, in TvStreamConfig config);
+    /**
+     * Set volume for this stream via AudioGain. (TBD)
+     */
+    void setVolume(float volume);
+
+    /**
+     * Dispatch key event to HDMI service. The events would be automatically converted to
+     * HDMI CEC commands. If the hardware is not representing an HDMI port, this method will fail.
+     */
+    boolean dispatchKeyEventToHdmi(in KeyEvent event);
+}
diff --git a/core/java/android/tv/ITvInputHardwareCallback.aidl b/core/java/android/tv/ITvInputHardwareCallback.aidl
new file mode 100644
index 0000000..83041be
--- /dev/null
+++ b/core/java/android/tv/ITvInputHardwareCallback.aidl
@@ -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.
+ */
+
+package android.tv;
+
+import android.tv.TvStreamConfig;
+
+/**
+ * @hide
+ */
+oneway interface ITvInputHardwareCallback {
+    void onReleased();
+    void onStreamConfigChanged(in TvStreamConfig[] configs);
+}
diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl
index b756aba..c6f8d79 100644
--- a/core/java/android/tv/ITvInputManager.aidl
+++ b/core/java/android/tv/ITvInputManager.aidl
@@ -19,7 +19,10 @@
 import android.content.ComponentName;
 import android.graphics.Rect;
 import android.net.Uri;
+import android.tv.ITvInputHardware;
+import android.tv.ITvInputHardwareCallback;
 import android.tv.ITvInputClient;
+import android.tv.TvInputHardwareInfo;
 import android.tv.TvInputInfo;
 import android.view.Surface;
 
@@ -46,4 +49,10 @@
             int userId);
     void relayoutOverlayView(in IBinder sessionToken, in Rect frame, int userId);
     void removeOverlayView(in IBinder sessionToken, int userId);
+
+    // For TV input hardware binding
+    List<TvInputHardwareInfo> getHardwareList();
+    ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback,
+            int userId);
+    void releaseTvInputHardware(int deviceId, in ITvInputHardware hardware, int userId);
 }
diff --git a/core/java/android/tv/TvInputHardwareInfo.aidl b/core/java/android/tv/TvInputHardwareInfo.aidl
new file mode 100644
index 0000000..484ab60
--- /dev/null
+++ b/core/java/android/tv/TvInputHardwareInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * 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.tv;
+
+parcelable TvInputHardwareInfo;
diff --git a/core/java/android/tv/TvInputHardwareInfo.java b/core/java/android/tv/TvInputHardwareInfo.java
new file mode 100644
index 0000000..b0dc58e
--- /dev/null
+++ b/core/java/android/tv/TvInputHardwareInfo.java
@@ -0,0 +1,93 @@
+/*
+ * 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.tv;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * Simple container for information about TV input hardware.
+ * Not for third-party developers.
+ *
+ * @hide
+ */
+public final class TvInputHardwareInfo implements Parcelable {
+    static final String TAG = "TvInputHardwareInfo";
+
+    // Match hardware/libhardware/include/hardware/tv_input.h
+    public static final int TV_INPUT_TYPE_HDMI           = 1;
+    public static final int TV_INPUT_TYPE_BUILT_IN_TUNER = 2;
+    public static final int TV_INPUT_TYPE_PASSTHROUGH    = 3;
+
+    public static final Parcelable.Creator<TvInputHardwareInfo> CREATOR =
+            new Parcelable.Creator<TvInputHardwareInfo>() {
+        @Override
+        public TvInputHardwareInfo createFromParcel(Parcel source) {
+            try {
+                TvInputHardwareInfo info = new TvInputHardwareInfo();
+                info.readFromParcel(source);
+                return info;
+            } catch (Exception e) {
+                Log.e(TAG, "Exception creating TvInputHardwareInfo from parcel", e);
+                return null;
+            }
+        }
+
+        @Override
+        public TvInputHardwareInfo[] newArray(int size) {
+            return new TvInputHardwareInfo[size];
+        }
+    };
+
+    private int mDeviceId;
+    private int mType;
+    // TODO: Add audio port & audio address for audio service.
+    // TODO: Add HDMI handle for HDMI service.
+
+    public TvInputHardwareInfo() { }
+
+    public TvInputHardwareInfo(int deviceId, int type) {
+        mDeviceId = deviceId;
+        mType = type;
+    }
+
+    public int getDeviceId() {
+        return mDeviceId;
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    // Parcelable
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mDeviceId);
+        dest.writeInt(mType);
+    }
+
+    public void readFromParcel(Parcel source) {
+        mDeviceId = source.readInt();
+        mType = source.readInt();
+    }
+}
diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java
index 50462cc..217e4b7 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/core/java/android/tv/TvInputInfo.java
@@ -39,7 +39,7 @@
     public TvInputInfo(ResolveInfo service) {
         mService = service;
         ServiceInfo si = service.serviceInfo;
-        mId = generateInputIdForComponenetName(new ComponentName(si.packageName, si.name));
+        mId = generateInputIdForComponentName(new ComponentName(si.packageName, si.name));
     }
 
     /**
@@ -134,7 +134,7 @@
      * @return the generated input id for the given {@code name}.
      * @hide
      */
-    public static final String generateInputIdForComponenetName(ComponentName name) {
+    public static final String generateInputIdForComponentName(ComponentName name) {
         return name.flattenToShortString();
     }
 
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index eeb738d..cb0142f 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -69,7 +69,7 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        mId = TvInputInfo.generateInputIdForComponenetName(
+        mId = TvInputInfo.generateInputIdForComponentName(
                 new ComponentName(getPackageName(), getClass().getName()));
     }
 
diff --git a/core/java/android/tv/TvStreamConfig.aidl b/core/java/android/tv/TvStreamConfig.aidl
new file mode 100644
index 0000000..4d0add4
--- /dev/null
+++ b/core/java/android/tv/TvStreamConfig.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * 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.tv;
+
+parcelable TvStreamConfig;
\ No newline at end of file
diff --git a/core/java/android/tv/TvStreamConfig.java b/core/java/android/tv/TvStreamConfig.java
new file mode 100644
index 0000000..03e63b1
--- /dev/null
+++ b/core/java/android/tv/TvStreamConfig.java
@@ -0,0 +1,157 @@
+/*
+ * 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.tv;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TvStreamConfig implements Parcelable {
+    static final String TAG = TvStreamConfig.class.getSimpleName();
+
+    public final static int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1;
+    public final static int STREAM_TYPE_BUFFER_PRODUCER = 2;
+
+    private int mStreamId;
+    private int mType;
+    // TODO: Revisit if max widht/height really make sense.
+    private int mMaxWidth;
+    private int mMaxHeight;
+    /**
+     * Generations are incremented once framework receives STREAM_CONFIGURATION_CHANGED event from
+     * HAL module. Framework should throw away outdated configurations and get new configurations
+     * via tv_input_device::get_stream_configurations().
+     */
+    private int mGeneration;
+
+    public static final Parcelable.Creator<TvStreamConfig> CREATOR =
+            new Parcelable.Creator<TvStreamConfig>() {
+        @Override
+        public TvStreamConfig createFromParcel(Parcel source) {
+            try {
+                return new Builder().
+                        streamId(source.readInt()).
+                        type(source.readInt()).
+                        maxWidth(source.readInt()).
+                        maxHeight(source.readInt()).
+                        generation(source.readInt()).build();
+            } catch (Exception e) {
+                Log.e(TAG, "Exception creating TvStreamConfig from parcel", e);
+                return null;
+            }
+        }
+
+        @Override
+        public TvStreamConfig[] newArray(int size) {
+            return new TvStreamConfig[size];
+        }
+    };
+
+    private TvStreamConfig() {}
+
+    public int getStreamId() {
+        return mStreamId;
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    public int getMaxWidth() {
+        return mMaxWidth;
+    }
+
+    public int getMaxHeight() {
+        return mMaxHeight;
+    }
+
+    public int getGeneration() {
+        return mGeneration;
+    }
+
+    // Parcelable
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mStreamId);
+        dest.writeInt(mType);
+        dest.writeInt(mMaxWidth);
+        dest.writeInt(mMaxHeight);
+        dest.writeInt(mGeneration);
+    }
+
+    /**
+     * A helper class for creating a TvStreamConfig object.
+     */
+    public static final class Builder {
+        private Integer mStreamId;
+        private Integer mType;
+        private Integer mMaxWidth;
+        private Integer mMaxHeight;
+        private Integer mGeneration;
+
+        public Builder() {
+        }
+
+        public Builder streamId(int streamId) {
+            mStreamId = streamId;
+            return this;
+        }
+
+        public Builder type(int type) {
+            mType = type;
+            return this;
+        }
+
+        public Builder maxWidth(int maxWidth) {
+            mMaxWidth = maxWidth;
+            return this;
+        }
+
+        public Builder maxHeight(int maxHeight) {
+            mMaxHeight = maxHeight;
+            return this;
+        }
+
+        public Builder generation(int generation) {
+            mGeneration = generation;
+            return this;
+        }
+
+        public TvStreamConfig build() {
+            if (mStreamId == null || mType == null || mMaxWidth == null || mMaxHeight == null
+                    || mGeneration == null) {
+                throw new UnsupportedOperationException();
+            }
+
+            TvStreamConfig config = new TvStreamConfig();
+            config.mStreamId = mStreamId;
+            config.mType = mType;
+            config.mMaxWidth = mMaxWidth;
+            config.mMaxHeight = mMaxHeight;
+            config.mGeneration = mGeneration;
+            return config;
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index a902ce7..3c4d83f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -579,6 +579,12 @@
     abstract void fence();
 
     /**
+     * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
+     */
+    public void notifyFramePending() {
+    }
+
+    /**
      * Describes a series of frames that should be drawn on screen as a graph.
      * Each frame is composed of 1 or more elements.
      */
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 704d516..9c9a939 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -33,8 +33,6 @@
 /**
  * Hardware renderer that proxies the rendering to a render thread. Most calls
  * are currently synchronous.
- * TODO: Make draw() async.
- * TODO: Figure out how to share the DisplayList between two threads (global lock?)
  *
  * The UI thread can block on the RenderThread, but RenderThread must never
  * block on the UI thread.
@@ -117,7 +115,7 @@
     @Override
     void destroyHardwareResources(View view) {
         destroyResources(view);
-        // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+        nFlushCaches(mNativeProxy, GLES20Canvas.FLUSH_CACHES_LAYERS);
     }
 
     private static void destroyResources(View view) {
@@ -291,6 +289,11 @@
     }
 
     @Override
+    public void notifyFramePending() {
+        nNotifyFramePending(mNativeProxy);
+    }
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             nDeleteProxy(mNativeProxy);
@@ -363,5 +366,8 @@
     private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
     private static native void nDestroyLayer(long nativeProxy, long layer);
 
+    private static native void nFlushCaches(long nativeProxy, int flushMode);
+
     private static native void nFence(long nativeProxy);
+    private static native void nNotifyFramePending(long nativeProxy);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6396781..ce266d7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10711,8 +10711,8 @@
      * {@link Drawable#getOutline(Outline)}. Manually setting the Outline with this method allows
      * this behavior to be overridden.
      * <p>
-     * If the outline is empty or is null, shadows will be cast from the
-     * bounds of the View.
+     * If the outline is {@link Outline#isEmpty()} or is <code>null</code>,
+     * shadows will not be cast.
      * <p>
      * Only outlines that return true from {@link Outline#canClip()} may be used for clipping.
      *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 148d9ec..c3bf295 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1000,6 +1000,17 @@
         }
     }
 
+    /**
+     * Notifies the HardwareRenderer that a new frame will be coming soon.
+     * Currently only {@link ThreadedRenderer} cares about this, and uses
+     * this knowledge to adjust the scheduling of off-thread animations
+     */
+    void notifyRendererOfFramePending() {
+        if (mAttachInfo.mHardwareRenderer != null) {
+            mAttachInfo.mHardwareRenderer.notifyFramePending();
+        }
+    }
+
     void scheduleTraversals() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
@@ -1009,6 +1020,7 @@
             if (!mUnbufferedInputDispatch) {
                 scheduleConsumeBatchedInput();
             }
+            notifyRendererOfFramePending();
         }
     }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 4fde1e4..1bb20c9 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1144,6 +1144,12 @@
     public void setLastInputMethodWindowLw(WindowState ime, WindowState target);
 
     /**
+     * Show the recents task list app.
+     * @hide
+     */
+    public void showRecentApps();
+
+    /**
      * @return The current height of the input method window.
      */
     public int getInputMethodWindowVisibleHeightLw();
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 1152e17..43f623b 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -256,6 +256,16 @@
     }
 
     @Override
+    public void invalidateDrawable(Drawable dr) {
+        super.invalidateDrawable(dr);
+
+        if (dr == mThumb) {
+            // Handle changes to thumb width and height.
+            requestLayout();
+        }
+    }
+
+    @Override
     void onProgressRefresh(float scale, boolean fromUser) {
         super.onProgressRefresh(scale, fromUser);
 
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 1533510..3ae9508 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.RemotableViewMethod;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -156,10 +157,36 @@
             mCheckMarkWidth = 0;
         }
         mCheckMarkDrawable = d;
-        // Do padding resolution. This will call internalSetPadding() and do a requestLayout() if needed.
+
+        // Do padding resolution. This will call internalSetPadding() and do a
+        // requestLayout() if needed.
         resolvePadding();
     }
 
+    @RemotableViewMethod
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+
+        if (mCheckMarkDrawable != null) {
+            mCheckMarkDrawable.setVisible(visibility == VISIBLE, false);
+        }
+    }
+
+    @Override
+    public void jumpDrawablesToCurrentState() {
+        super.jumpDrawablesToCurrentState();
+
+        if (mCheckMarkDrawable != null) {
+            mCheckMarkDrawable.jumpToCurrentState();
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return who == mCheckMarkDrawable || super.verifyDrawable(who);
+    }
+
     /**
      * Gets the checkmark drawable
      *
@@ -249,6 +276,11 @@
             }
             checkMarkDrawable.setBounds(mScrollX + left, top, mScrollX + right, bottom);
             checkMarkDrawable.draw(canvas);
+
+            final Drawable background = getBackground();
+            if (background != null) {
+                background.setHotspotBounds(mScrollX + left, top, mScrollX + right, bottom);
+            }
         }
     }
     
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 97f89aa..defc26c 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -1012,6 +1012,8 @@
             LayoutParams lp = getLayoutParams(c);
             if (firstPass) {
                 measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
+                mHorizontalAxis.recordOriginalMeasurement(i);
+                mVerticalAxis.recordOriginalMeasurement(i);
             } else {
                 boolean horizontal = (mOrientation == HORIZONTAL);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
@@ -1239,6 +1241,11 @@
         public int[] locations;
         public boolean locationsValid = false;
 
+        public boolean hasWeights;
+        public boolean hasWeightsValid = false;
+        public int[] originalMeasurements;
+        public int[] deltas;
+
         boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
 
         private MutableInt parentMin = new MutableInt(0);
@@ -1315,7 +1322,10 @@
                 // we must include views that are GONE here, see introductory javadoc
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
+                int size = (spec.weight == 0) ?
+                        getMeasurementIncludingMargin(c, horizontal) :
+                        getOriginalMeasurements()[i] + getDeltas()[i];
+                groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size);
             }
         }
 
@@ -1691,50 +1701,67 @@
             solve(getArcs(), a);
         }
 
-        private void resetDeltas() {
-            Bounds[] values = getGroupBounds().values;
-            for (int i = 0, N = values.length; i < N; i++) {
-                values[i].shareOfDelta = 0;
-            }
-        }
-
-        private boolean requiresWeightDistribution() {
-            Bounds[] values = getGroupBounds().values;
-            for (int i = 0, N = values.length; i < N; i++) {
-                if (values[i].weight != 0) {
+        private boolean computeHasWeights() {
+            for (int i = 0, N = getChildCount(); i < N; i++) {
+                LayoutParams lp = getLayoutParams(getChildAt(i));
+                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+                if (spec.weight != 0) {
                     return true;
                 }
             }
             return false;
         }
 
-        private void shareOutDelta(int[] locations) {
-            PackedMap<Spec, Bounds> groupBounds = getGroupBounds();
-            Spec[] specs = groupBounds.keys;
-            Bounds[] bounds = groupBounds.values;
+        private boolean hasWeights() {
+            if (!hasWeightsValid) {
+                hasWeights = computeHasWeights();
+                hasWeightsValid = true;
+            }
+            return hasWeights;
+        }
+
+        public int[] getOriginalMeasurements() {
+            if (originalMeasurements == null) {
+                originalMeasurements = new int[getChildCount()];
+            }
+            return originalMeasurements;
+        }
+
+        private void recordOriginalMeasurement(int i) {
+            if (hasWeights()) {
+                getOriginalMeasurements()[i] = getMeasurementIncludingMargin(getChildAt(i), horizontal);
+            }
+        }
+
+        public int[] getDeltas() {
+            if (deltas == null) {
+                deltas = new int[getChildCount()];
+            }
+            return deltas;
+        }
+
+        private void shareOutDelta() {
             int totalDelta = 0;
             float totalWeight = 0;
-            final int N = bounds.length;
-
-            for (int i = 0; i < N; i++) {
-                Spec spec = specs[i];
-                Bounds bound = bounds[i];
-                if (bound.weight != 0) {
-                    int minSize = bound.size(true);
-                    Interval span = spec.span;
-                    int actualSize = locations[span.max] - locations[span.min];
-                    int delta = actualSize - minSize;
+            for (int i = 0, N = getChildCount(); i < N; i++) {
+                View c = getChildAt(i);
+                LayoutParams lp = getLayoutParams(c);
+                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+                float weight = spec.weight;
+                if (weight != 0) {
+                    int delta = getMeasurement(c, horizontal) - getOriginalMeasurements()[i];
                     totalDelta += delta;
-                    totalWeight += bound.weight;
+                    totalWeight += weight;
                 }
             }
-            for (int i = 0; i < N; i++) {
-                Bounds bound = bounds[i];
-                float weight = bound.weight;
+            for (int i = 0, N = getChildCount(); i < N; i++) {
+                LayoutParams lp = getLayoutParams(getChildAt(i));
+                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+                float weight = spec.weight;
                 if (weight != 0) {
                     int delta = Math.round((weight * totalDelta / totalWeight));
-                    bound.shareOfDelta = delta;
-                    // the two adjustments below compensate for the rounding above
+                    deltas[i] = delta;
+                    // the two adjustments below are to counter the above rounding and avoid off-by-ones at the end
                     totalDelta -= delta;
                     totalWeight -= weight;
                 }
@@ -1742,19 +1769,22 @@
         }
 
         private void solveAndDistributeSpace(int[] a) {
-            resetDeltas();
+            Arrays.fill(getDeltas(), 0);
             solve(a);
-            if (requiresWeightDistribution()) {
-                shareOutDelta(a);
-                arcsValid = false;
-                forwardLinksValid = false;
-                backwardLinksValid = false;
-                solve(a);
-            }
+            shareOutDelta();
+            arcsValid = false;
+            forwardLinksValid = false;
+            backwardLinksValid = false;
+            groupBoundsValid = false;
+            solve(a);
         }
 
         private void computeLocations(int[] a) {
-            solveAndDistributeSpace(a);
+            if (!hasWeights()) {
+                solve(a);
+            } else {
+                solveAndDistributeSpace(a);
+            }
             if (!orderPreserved) {
                 // Solve returns the smallest solution to the constraint system for which all
                 // values are positive. One value is therefore zero - though if the row/col
@@ -1837,6 +1867,10 @@
 
             locations = null;
 
+            originalMeasurements = null;
+            deltas = null;
+            hasWeightsValid = false;
+
             invalidateValues();
         }
 
@@ -1872,21 +1906,7 @@
      * method.
      * <p>
      * The weight property is also included in Spec and specifies the proportion of any
-     * excess space that is due to the enclosing row or column.
-     * GridLayout's model of flexibility and weight is broadly based on the physical properties of
-     * systems of mechanical springs. For example, a column in a GridLayout is modeled as
-     * if a set of springs were attached in parallel at their ends. Columns are therefore
-     * flexible only if and only if all views inside them are flexible. Similarly, the combined
-     * weight of a column is defined as the <em>minimum</em> of the weights of the components it
-     * contains. So, if any one component in a column of components has a weight of zero,
-     * the entire group has a weight of zero and will not receive any of the
-     * excess space that GridLayout distributes in its second
-     * (internal) layout pass. The default weight of a component is zero,
-     * reflecting inflexibility, but the default weight of a column (with nothing in it)
-     * is effectively infinite, reflecting the fact that a parallel group of
-     * springs is infinitely flexible when it contains no springs.
-     * <p>
-     * The above comments apply equally to rows and groups of rows and columns.
+     * excess space that is due to the associated view.
      *
      * <h4>WRAP_CONTENT and MATCH_PARENT</h4>
      *
@@ -2329,8 +2349,6 @@
         public int before;
         public int after;
         public int flexibility; // we're flexible iff all included specs are flexible
-        public float weight; // the min of the weights of the individual specs
-        public int shareOfDelta;
 
         private Bounds() {
             reset();
@@ -2340,7 +2358,6 @@
             before = Integer.MIN_VALUE;
             after = Integer.MIN_VALUE;
             flexibility = CAN_STRETCH; // from the above, we're flexible when empty
-            weight = Float.MAX_VALUE; // default  is large => row/cols take all slack when empty
         }
 
         protected void include(int before, int after) {
@@ -2354,18 +2371,16 @@
                     return MAX_SIZE;
                 }
             }
-            return before + after + shareOfDelta;
+            return before + after;
         }
 
         protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
             return before - a.getAlignmentValue(c, size, gl.getLayoutMode());
         }
 
-        protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
+        protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) {
             this.flexibility &= spec.getFlexibility();
-            weight = Math.min(weight, spec.weight);
             boolean horizontal = axis.horizontal;
-            int size = gl.getMeasurementIncludingMargin(c, horizontal);
             Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
             // todo test this works correctly when the returned value is UNDEFINED
             int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index ad1a023..c5c6e64 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -951,9 +951,8 @@
 
         final int[] myDrawableState = getDrawableState();
 
-        if (mThumbDrawable != null && mThumbDrawable.setState(myDrawableState)) {
-            // Handle changes to thumb width and height.
-            requestLayout();
+        if (mThumbDrawable != null) {
+            mThumbDrawable.setState(myDrawableState);
         }
 
         if (mTrackDrawable != null) {
@@ -964,6 +963,16 @@
     }
 
     @Override
+    public void invalidateDrawable(Drawable drawable) {
+        super.invalidateDrawable(drawable);
+
+        if (drawable == mThumbDrawable) {
+            // Handle changes to thumb width and height.
+            requestLayout();
+        }
+    }
+
+    @Override
     protected boolean verifyDrawable(Drawable who) {
         return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
     }
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 664f9db..5547a10 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -1026,7 +1026,7 @@
                         ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;
                 if (mCursor == null) {
                     adapter = (mAdapter != null) ? mAdapter
-                            : new ArrayAdapter<CharSequence>(mContext, layout, R.id.text1, mItems);
+                            : new CheckedItemAdapter(mContext, layout, R.id.text1, mItems);
                 } else {
                     adapter = new SimpleCursorAdapter(mContext, layout, 
                             mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1});
@@ -1081,4 +1081,20 @@
         }
     }
 
+    private static class CheckedItemAdapter extends ArrayAdapter<CharSequence> {
+        public CheckedItemAdapter(Context context, int resource, int textViewResourceId,
+                CharSequence[] objects) {
+            super(context, resource, textViewResourceId, objects);
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 47ef65a..01e5d40 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -35,8 +35,8 @@
 
 
 /*
- * This is used in conjunction with DevicePolicyManager.setForwardingIntents to enable intents to be
- * passed in and out of a managed profile.
+ * 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.
  */
 
 public class IntentForwarderActivity extends Activity  {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 591267e..183dd05 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -484,8 +484,7 @@
 
             mList.clear();
             if (mBaseResolveList != null) {
-                currentResolveList = mBaseResolveList;
-                mOrigResolveList = null;
+                currentResolveList = mOrigResolveList = mBaseResolveList;
             } else {
                 currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
                         mIntent, PackageManager.MATCH_DEFAULT_ONLY
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index 70c77b8..df96488 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -271,8 +271,83 @@
         }
     }
 
+    private static class DynamicRotationList {
+        private static final String TAG = DynamicRotationList.class.getSimpleName();
+        private final List<ImeSubtypeListItem> mImeSubtypeList;
+        private final int[] mUsageHistoryOfSubtypeListItemIndex;
+
+        public DynamicRotationList(final List<ImeSubtypeListItem> imeSubtypeListItems) {
+            mImeSubtypeList = imeSubtypeListItems;
+            mUsageHistoryOfSubtypeListItemIndex = new int[mImeSubtypeList.size()];
+            final int N = mImeSubtypeList.size();
+            for (int i = 0; i < N; i++) {
+                mUsageHistoryOfSubtypeListItemIndex[i] = i;
+            }
+        }
+
+        /**
+         * Returns the index of the specified object in
+         * {@link #mUsageHistoryOfSubtypeListItemIndex}.
+         * <p>We call the index of {@link #mUsageHistoryOfSubtypeListItemIndex} as "Usage Rank"
+         * so as not to be confused with the index in {@link #mImeSubtypeList}.
+         * @return -1 when the specified item doesn't belong to {@link #mImeSubtypeList} actually.
+         */
+        private int getUsageRank(final InputMethodInfo imi, InputMethodSubtype subtype) {
+            final int currentSubtypeId = calculateSubtypeId(imi, subtype);
+            final int N = mUsageHistoryOfSubtypeListItemIndex.length;
+            for (int usageRank = 0; usageRank < N; usageRank++) {
+                final int subtypeListItemIndex = mUsageHistoryOfSubtypeListItemIndex[usageRank];
+                final ImeSubtypeListItem subtypeListItem =
+                        mImeSubtypeList.get(subtypeListItemIndex);
+                if (subtypeListItem.mImi.equals(imi) &&
+                        subtypeListItem.mSubtypeId == currentSubtypeId) {
+                    return usageRank;
+                }
+            }
+            // Not found in the known IME/Subtype list.
+            return -1;
+        }
+
+        public void onUserAction(InputMethodInfo imi, InputMethodSubtype subtype) {
+            final int currentUsageRank = getUsageRank(imi, subtype);
+            // Do nothing if currentUsageRank == -1 (not found), or currentUsageRank == 0
+            if (currentUsageRank <= 0) {
+                return;
+            }
+            final int currentItemIndex = mUsageHistoryOfSubtypeListItemIndex[currentUsageRank];
+            System.arraycopy(mUsageHistoryOfSubtypeListItemIndex, 0,
+                    mUsageHistoryOfSubtypeListItemIndex, 1, currentUsageRank);
+            mUsageHistoryOfSubtypeListItemIndex[0] = currentItemIndex;
+        }
+
+        public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
+                InputMethodInfo imi, InputMethodSubtype subtype) {
+            int currentUsageRank = getUsageRank(imi, subtype);
+            if (currentUsageRank < 0) {
+                if (DEBUG) {
+                    Slog.d(TAG, "IME/subtype is not found: " + imi.getId() + ", " + subtype);
+                }
+                return null;
+            }
+            final int N = mUsageHistoryOfSubtypeListItemIndex.length;
+            for (int i = 1; i < N; i++) {
+                final int subtypeListItemRank = (currentUsageRank + i) % N;
+                final int subtypeListItemIndex =
+                        mUsageHistoryOfSubtypeListItemIndex[subtypeListItemRank];
+                final ImeSubtypeListItem subtypeListItem =
+                        mImeSubtypeList.get(subtypeListItemIndex);
+                if (onlyCurrentIme && !imi.equals(subtypeListItem.mImi)) {
+                    continue;
+                }
+                return subtypeListItem;
+            }
+            return null;
+        }
+    }
+
     @VisibleForTesting
     public static class ControllerImpl {
+        // TODO: Switch to DynamicRotationList for smarter rotation.
         private final StaticRotationList mSwitchingAwareSubtypeList;
         private final StaticRotationList mSwitchingUnawareSubtypeList;
 
@@ -297,6 +372,16 @@
             }
         }
 
+        public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
+            if (imi == null) {
+                return;
+            }
+            // TODO: Enable the following code when DynamicRotationList is enabled.
+            // if (imi.supportsSwitchingToNextInputMethod()) {
+            //     mSwitchingAwareSubtypeList.onUserAction(imi, subtype);
+            // }
+        }
+
         private static List<ImeSubtypeListItem> filterImeSubtypeList(
                 final List<ImeSubtypeListItem> items,
                 final boolean supportsSwitchingToNextInputMethod) {
@@ -327,9 +412,14 @@
         return new InputMethodSubtypeSwitchingController(settings, context);
     }
 
-    // TODO: write unit tests for this method and the logic that determines the next subtype
     public void onCommitTextLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
-        // TODO: Implement this.
+        if (mController == null) {
+            if (DEBUG) {
+                Log.e(TAG, "mController shouldn't be null.");
+            }
+            return;
+        }
+        mController.onUserActionLocked(imi, subtype);
     }
 
     public void resetCircularListLocked(Context context) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 24e55e4..ed9f9bc 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -2342,7 +2342,13 @@
             // Only care about partial wake locks, since full wake locks
             // will be canceled when the user puts the screen to sleep.
             aggregateLastWakeupUptimeLocked(uptime);
-            historyName = historyName == null || mRecordAllWakeLocks ? name : historyName;
+            if (mRecordAllWakeLocks) {
+                if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, name, uid, 0)) {
+                    addHistoryEventLocked(elapsedRealtime, uptime,
+                            HistoryItem.EVENT_WAKE_LOCK_START, name, uid);
+                }
+            }
+            historyName = historyName == null ? name : historyName;
             if (mWakeLockNesting == 0) {
                 mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
@@ -2352,7 +2358,7 @@
                 mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                 mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
-            } else if (!mRecordAllWakeLocks && !mWakeLockImportant && !unimportantForLogging) {
+            } else if (!mWakeLockImportant && !unimportantForLogging) {
                 if (mHistoryLastWritten.wakelockTag != null) {
                     // We'll try to update the last tag.
                     mHistoryLastWritten.wakelockTag = null;
@@ -2362,14 +2368,6 @@
                     addHistoryRecordLocked(elapsedRealtime, uptime);
                 }
                 mWakeLockImportant = true;
-            } else if (mRecordAllWakeLocks) {
-                if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
-                        uid, 0)) {
-                    mWakeLockNesting++;
-                    return;
-                }
-                addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_START,
-                        historyName, uid);
             }
             mWakeLockNesting++;
         }
@@ -2387,28 +2385,19 @@
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             mWakeLockNesting--;
-            historyName = historyName == null || mRecordAllWakeLocks ? name : historyName;
+            if (mRecordAllWakeLocks) {
+                if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, name, uid, 0)) {
+                    addHistoryEventLocked(elapsedRealtime, uptime,
+                            HistoryItem.EVENT_WAKE_LOCK_FINISH, name, uid);
+                }
+            }
             if (mWakeLockNesting == 0) {
                 mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
-                if (mRecordAllWakeLocks
-                        || (historyName != null && !historyName.equals(mInitialAcquireWakeName))
-                        || uid != mInitialAcquireWakeUid) {
-                    mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                    mHistoryCur.wakelockTag.string = historyName;
-                    mHistoryCur.wakelockTag.uid = uid;
-                }
                 mInitialAcquireWakeName = null;
                 mInitialAcquireWakeUid = -1;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
-            } else if (mRecordAllWakeLocks) {
-                if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
-                        uid, 0)) {
-                    return;
-                }
-                addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_FINISH,
-                        historyName, uid);
             }
         }
         if (uid >= 0) {
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 5b59599..dca9921 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -220,31 +220,77 @@
      * @see #readMapXml
      */
     public static final void writeMapXml(Map val, String name, XmlSerializer out)
-    throws XmlPullParserException, java.io.IOException
-    {
+            throws XmlPullParserException, java.io.IOException {
+        writeMapXml(val, name, out, null);
+    }
+
+    /**
+     * Flatten a Map into an XmlSerializer.  The map can later be read back
+     * with readThisMapXml().
+     *
+     * @param val The map to be flattened.
+     * @param name Name attribute to include with this list's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the map into.
+     * @param callback Method to call when an Object type is not recognized.
+     *
+     * @see #writeMapXml(Map, OutputStream)
+     * @see #writeListXml
+     * @see #writeValueXml
+     * @see #readMapXml
+     *
+     * @hide
+     */
+    public static final void writeMapXml(Map val, String name, XmlSerializer out,
+            WriteMapCallback callback) throws XmlPullParserException, java.io.IOException {
+
         if (val == null) {
             out.startTag(null, "null");
             out.endTag(null, "null");
             return;
         }
 
-        Set s = val.entrySet();
-        Iterator i = s.iterator();
-
         out.startTag(null, "map");
         if (name != null) {
             out.attribute(null, "name", name);
         }
 
-        while (i.hasNext()) {
-            Map.Entry e = (Map.Entry)i.next();
-            writeValueXml(e.getValue(), (String)e.getKey(), out);
-        }
+        writeMapXml(val, out, callback);
 
         out.endTag(null, "map");
     }
 
     /**
+     * Flatten a Map into an XmlSerializer.  The map can later be read back
+     * with readThisMapXml(). This method presumes that the start tag and
+     * name attribute have already been written and does not write an end tag.
+     *
+     * @param val The map to be flattened.
+     * @param out XmlSerializer to write the map into.
+     *
+     * @see #writeMapXml(Map, OutputStream)
+     * @see #writeListXml
+     * @see #writeValueXml
+     * @see #readMapXml
+     *
+     * @hide
+     */
+    public static final void writeMapXml(Map val, XmlSerializer out,
+            WriteMapCallback callback) throws XmlPullParserException, java.io.IOException {
+        if (val == null) {
+            return;
+        }
+
+        Set s = val.entrySet();
+        Iterator i = s.iterator();
+
+        while (i.hasNext()) {
+            Map.Entry e = (Map.Entry)i.next();
+            writeValueXml(e.getValue(), (String)e.getKey(), out, callback);
+        }
+    }
+
+    /**
      * Flatten a List into an XmlSerializer.  The list can later be read back
      * with readThisListXml().
      *
@@ -387,6 +433,123 @@
     }
 
     /**
+     * Flatten a long[] into an XmlSerializer.  The list can later be read back
+     * with readThisLongArrayXml().
+     *
+     * @param val The long array to be flattened.
+     * @param name Name attribute to include with this array's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the array into.
+     *
+     * @see #writeMapXml
+     * @see #writeValueXml
+     * @see #readThisIntArrayXml
+     */
+    public static final void writeLongArrayXml(long[] val, String name, XmlSerializer out)
+            throws XmlPullParserException, java.io.IOException {
+
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        out.startTag(null, "long-array");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        final int N = val.length;
+        out.attribute(null, "num", Integer.toString(N));
+
+        for (int i=0; i<N; i++) {
+            out.startTag(null, "item");
+            out.attribute(null, "value", Long.toString(val[i]));
+            out.endTag(null, "item");
+        }
+
+        out.endTag(null, "long-array");
+    }
+
+    /**
+     * Flatten a double[] into an XmlSerializer.  The list can later be read back
+     * with readThisDoubleArrayXml().
+     *
+     * @param val The double array to be flattened.
+     * @param name Name attribute to include with this array's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the array into.
+     *
+     * @see #writeMapXml
+     * @see #writeValueXml
+     * @see #readThisIntArrayXml
+     */
+    public static final void writeDoubleArrayXml(double[] val, String name, XmlSerializer out)
+            throws XmlPullParserException, java.io.IOException {
+
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        out.startTag(null, "double-array");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        final int N = val.length;
+        out.attribute(null, "num", Integer.toString(N));
+
+        for (int i=0; i<N; i++) {
+            out.startTag(null, "item");
+            out.attribute(null, "value", Double.toString(val[i]));
+            out.endTag(null, "item");
+        }
+
+        out.endTag(null, "double-array");
+    }
+
+    /**
+     * Flatten a String[] into an XmlSerializer.  The list can later be read back
+     * with readThisStringArrayXml().
+     *
+     * @param val The long array to be flattened.
+     * @param name Name attribute to include with this array's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the array into.
+     *
+     * @see #writeMapXml
+     * @see #writeValueXml
+     * @see #readThisIntArrayXml
+     */
+    public static final void writeStringArrayXml(String[] val, String name, XmlSerializer out)
+            throws XmlPullParserException, java.io.IOException {
+
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        out.startTag(null, "string-array");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        final int N = val.length;
+        out.attribute(null, "num", Integer.toString(N));
+
+        for (int i=0; i<N; i++) {
+            out.startTag(null, "item");
+            out.attribute(null, "value", val[i]);
+            out.endTag(null, "item");
+        }
+
+        out.endTag(null, "string-array");
+    }
+
+    /**
      * Flatten an object's value into an XmlSerializer.  The value can later
      * be read back with readThisValueXml().
      *
@@ -403,8 +566,29 @@
      * @see #readValueXml
      */
     public static final void writeValueXml(Object v, String name, XmlSerializer out)
-    throws XmlPullParserException, java.io.IOException
-    {
+            throws XmlPullParserException, java.io.IOException {
+        writeValueXml(v, name, out, null);
+    }
+
+    /**
+     * Flatten an object's value into an XmlSerializer.  The value can later
+     * be read back with readThisValueXml().
+     *
+     * Currently supported value types are: null, String, Integer, Long,
+     * Float, Double Boolean, Map, List.
+     *
+     * @param v The object to be flattened.
+     * @param name Name attribute to include with this value's tag, or null
+     *             for none.
+     * @param out XmlSerializer to write the object into.
+     * @param callback Handler for Object types not recognized.
+     *
+     * @see #writeMapXml
+     * @see #writeListXml
+     * @see #readValueXml
+     */
+    private static final void writeValueXml(Object v, String name, XmlSerializer out,
+            WriteMapCallback callback)  throws XmlPullParserException, java.io.IOException {
         String typeStr;
         if (v == null) {
             out.startTag(null, "null");
@@ -437,14 +621,23 @@
         } else if (v instanceof int[]) {
             writeIntArrayXml((int[])v, name, out);
             return;
+        } else if (v instanceof long[]) {
+            writeLongArrayXml((long[])v, name, out);
+            return;
+        } else if (v instanceof double[]) {
+            writeDoubleArrayXml((double[])v, name, out);
+            return;
+        } else if (v instanceof String[]) {
+            writeStringArrayXml((String[])v, name, out);
+            return;
         } else if (v instanceof Map) {
             writeMapXml((Map)v, name, out);
             return;
         } else if (v instanceof List) {
-            writeListXml((List)v, name, out);
+            writeListXml((List) v, name, out);
             return;
         } else if (v instanceof Set) {
-            writeSetXml((Set)v, name, out);
+            writeSetXml((Set) v, name, out);
             return;
         } else if (v instanceof CharSequence) {
             // XXX This is to allow us to at least write something if
@@ -457,6 +650,9 @@
             out.text(v.toString());
             out.endTag(null, "string");
             return;
+        } else if (callback != null) {
+            callback.writeUnknownObject(v, name, out);
+            return;
         } else {
             throw new RuntimeException("writeValueXml: unable to write value " + v);
         }
@@ -550,14 +746,35 @@
      * @see #readMapXml
      */
     public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag,
-            String[] name) throws XmlPullParserException, java.io.IOException
+            String[] name) throws XmlPullParserException, java.io.IOException {
+        return readThisMapXml(parser, endTag, name, null);
+    }
+
+    /**
+     * Read a HashMap object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeMapXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the map.
+     *
+     * @param parser The XmlPullParser from which to read the map data.
+     * @param endTag Name of the tag that will end the map, usually "map".
+     * @param name An array of one string, used to return the name attribute
+     *             of the map's tag.
+     *
+     * @return HashMap The newly generated map.
+     *
+     * @see #readMapXml
+     * @hide
+     */
+    public static final HashMap<String, ?> readThisMapXml(XmlPullParser parser, String endTag,
+            String[] name, ReadMapCallback callback)
+            throws XmlPullParserException, java.io.IOException
     {
         HashMap<String, Object> map = new HashMap<String, Object>();
 
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                Object val = readThisValueXml(parser, name);
+                Object val = readThisValueXml(parser, name, callback);
                 map.put(name[0], val);
             } else if (eventType == parser.END_TAG) {
                 if (parser.getName().equals(endTag)) {
@@ -587,15 +804,34 @@
      *
      * @see #readListXml
      */
-    public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, String[] name)
-    throws XmlPullParserException, java.io.IOException
-    {
+    public static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
+            String[] name) throws XmlPullParserException, java.io.IOException {
+        return readThisListXml(parser, endTag, name, null);
+    }
+
+    /**
+     * Read an ArrayList object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeListXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the list.
+     *
+     * @param parser The XmlPullParser from which to read the list data.
+     * @param endTag Name of the tag that will end the list, usually "list".
+     * @param name An array of one string, used to return the name attribute
+     *             of the list's tag.
+     *
+     * @return HashMap The newly generated list.
+     *
+     * @see #readListXml
+     */
+    private static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
+            String[] name, ReadMapCallback callback)
+            throws XmlPullParserException, java.io.IOException {
         ArrayList list = new ArrayList();
 
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                Object val = readThisValueXml(parser, name);
+                Object val = readThisValueXml(parser, name, callback);
                 list.add(val);
                 //System.out.println("Adding to list: " + val);
             } else if (eventType == parser.END_TAG) {
@@ -611,7 +847,29 @@
         throw new XmlPullParserException(
             "Document ended before " + endTag + " end tag");
     }
-    
+
+    /**
+     * Read a HashSet object from an XmlPullParser. The XML data could previously
+     * have been generated by writeSetXml(). The XmlPullParser must be positioned
+     * <em>after</em> the tag that begins the set.
+     *
+     * @param parser The XmlPullParser from which to read the set data.
+     * @param endTag Name of the tag that will end the set, usually "set".
+     * @param name An array of one string, used to return the name attribute
+     *             of the set's tag.
+     *
+     * @return HashSet The newly generated set.
+     *
+     * @throws XmlPullParserException
+     * @throws java.io.IOException
+     *
+     * @see #readSetXml
+     */
+    public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name)
+            throws XmlPullParserException, java.io.IOException {
+        return readThisSetXml(parser, endTag, name, null);
+    }
+
     /**
      * Read a HashSet object from an XmlPullParser. The XML data could previously
      * have been generated by writeSetXml(). The XmlPullParser must be positioned
@@ -628,15 +886,16 @@
      * @throws java.io.IOException
      * 
      * @see #readSetXml
+     * @hide
      */
-    public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name)
-            throws XmlPullParserException, java.io.IOException {
+    private static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name,
+            ReadMapCallback callback) throws XmlPullParserException, java.io.IOException {
         HashSet set = new HashSet();
         
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                Object val = readThisValueXml(parser, name);
+                Object val = readThisValueXml(parser, name, callback);
                 set.add(val);
                 //System.out.println("Adding to set: " + val);
             } else if (eventType == parser.END_TAG) {
@@ -681,6 +940,7 @@
             throw new XmlPullParserException(
                     "Not a number in num attribute in byte-array");
         }
+        parser.next();
 
         int[] array = new int[num];
         int i = 0;
@@ -722,6 +982,187 @@
     }
 
     /**
+     * Read a long[] object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeLongArrayXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the list.
+     *
+     * @param parser The XmlPullParser from which to read the list data.
+     * @param endTag Name of the tag that will end the list, usually "list".
+     * @param name An array of one string, used to return the name attribute
+     *             of the list's tag.
+     *
+     * @return Returns a newly generated long[].
+     *
+     * @see #readListXml
+     */
+    public static final long[] readThisLongArrayXml(XmlPullParser parser,
+            String endTag, String[] name)
+            throws XmlPullParserException, java.io.IOException {
+
+        int num;
+        try {
+            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
+        } catch (NullPointerException e) {
+            throw new XmlPullParserException("Need num attribute in long-array");
+        } catch (NumberFormatException e) {
+            throw new XmlPullParserException("Not a number in num attribute in long-array");
+        }
+        parser.next();
+
+        long[] array = new long[num];
+        int i = 0;
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                if (parser.getName().equals("item")) {
+                    try {
+                        array[i] = Long.parseLong(parser.getAttributeValue(null, "value"));
+                    } catch (NullPointerException e) {
+                        throw new XmlPullParserException("Need value attribute in item");
+                    } catch (NumberFormatException e) {
+                        throw new XmlPullParserException("Not a number in value attribute in item");
+                    }
+                } else {
+                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
+                }
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return array;
+                } else if (parser.getName().equals("item")) {
+                    i++;
+                } else {
+                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
+                            parser.getName());
+                }
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
+    }
+
+    /**
+     * Read a double[] object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeDoubleArrayXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the list.
+     *
+     * @param parser The XmlPullParser from which to read the list data.
+     * @param endTag Name of the tag that will end the list, usually "double-array".
+     * @param name An array of one string, used to return the name attribute
+     *             of the list's tag.
+     *
+     * @return Returns a newly generated double[].
+     *
+     * @see #readListXml
+     */
+    public static final double[] readThisDoubleArrayXml(XmlPullParser parser, String endTag,
+            String[] name) throws XmlPullParserException, java.io.IOException {
+
+        int num;
+        try {
+            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
+        } catch (NullPointerException e) {
+            throw new XmlPullParserException("Need num attribute in double-array");
+        } catch (NumberFormatException e) {
+            throw new XmlPullParserException("Not a number in num attribute in double-array");
+        }
+        parser.next();
+
+        double[] array = new double[num];
+        int i = 0;
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                if (parser.getName().equals("item")) {
+                    try {
+                        array[i] = Double.parseDouble(parser.getAttributeValue(null, "value"));
+                    } catch (NullPointerException e) {
+                        throw new XmlPullParserException("Need value attribute in item");
+                    } catch (NumberFormatException e) {
+                        throw new XmlPullParserException("Not a number in value attribute in item");
+                    }
+                } else {
+                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
+                }
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return array;
+                } else if (parser.getName().equals("item")) {
+                    i++;
+                } else {
+                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
+                            parser.getName());
+                }
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
+    }
+
+    /**
+     * Read a String[] object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeStringArrayXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the list.
+     *
+     * @param parser The XmlPullParser from which to read the list data.
+     * @param endTag Name of the tag that will end the list, usually "string-array".
+     * @param name An array of one string, used to return the name attribute
+     *             of the list's tag.
+     *
+     * @return Returns a newly generated String[].
+     *
+     * @see #readListXml
+     */
+    public static final String[] readThisStringArrayXml(XmlPullParser parser, String endTag,
+            String[] name) throws XmlPullParserException, java.io.IOException {
+
+        int num;
+        try {
+            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
+        } catch (NullPointerException e) {
+            throw new XmlPullParserException("Need num attribute in string-array");
+        } catch (NumberFormatException e) {
+            throw new XmlPullParserException("Not a number in num attribute in string-array");
+        }
+        parser.next();
+
+        String[] array = new String[num];
+        int i = 0;
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                if (parser.getName().equals("item")) {
+                    try {
+                        array[i] = parser.getAttributeValue(null, "value");
+                    } catch (NullPointerException e) {
+                        throw new XmlPullParserException("Need value attribute in item");
+                    } catch (NumberFormatException e) {
+                        throw new XmlPullParserException("Not a number in value attribute in item");
+                    }
+                } else {
+                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
+                }
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return array;
+                } else if (parser.getName().equals("item")) {
+                    i++;
+                } else {
+                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
+                            parser.getName());
+                }
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
+    }
+
+    /**
      * Read a flattened object from an XmlPullParser.  The XML data could
      * previously have been written with writeMapXml(), writeListXml(), or
      * writeValueXml().  The XmlPullParser must be positioned <em>at</em> the
@@ -743,7 +1184,7 @@
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                return readThisValueXml(parser, name);
+                return readThisValueXml(parser, name, null);
             } else if (eventType == parser.END_TAG) {
                 throw new XmlPullParserException(
                     "Unexpected end tag at: " + parser.getName());
@@ -758,9 +1199,8 @@
             "Unexpected end of document");
     }
 
-    private static final Object readThisValueXml(XmlPullParser parser, String[] name)
-    throws XmlPullParserException, java.io.IOException
-    {
+    private static final Object readThisValueXml(XmlPullParser parser, String[] name,
+            ReadMapCallback callback)  throws XmlPullParserException, java.io.IOException {
         final String valueName = parser.getAttributeValue(null, "name");
         final String tagName = parser.getName();
 
@@ -794,11 +1234,25 @@
         } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) {
             // all work already done by readThisPrimitiveValueXml
         } else if (tagName.equals("int-array")) {
-            parser.next();
             res = readThisIntArrayXml(parser, "int-array", name);
             name[0] = valueName;
             //System.out.println("Returning value for " + valueName + ": " + res);
             return res;
+        } else if (tagName.equals("long-array")) {
+            res = readThisLongArrayXml(parser, "long-array", name);
+            name[0] = valueName;
+            //System.out.println("Returning value for " + valueName + ": " + res);
+            return res;
+        } else if (tagName.equals("double-array")) {
+            res = readThisDoubleArrayXml(parser, "double-array", name);
+            name[0] = valueName;
+            //System.out.println("Returning value for " + valueName + ": " + res);
+            return res;
+        } else if (tagName.equals("string-array")) {
+            res = readThisStringArrayXml(parser, "string-array", name);
+            name[0] = valueName;
+            //System.out.println("Returning value for " + valueName + ": " + res);
+            return res;
         } else if (tagName.equals("map")) {
             parser.next();
             res = readThisMapXml(parser, "map", name);
@@ -817,9 +1271,12 @@
             name[0] = valueName;
             //System.out.println("Returning value for " + valueName + ": " + res);
             return res;
+        } else if (callback != null) {
+            res = callback.readThisUnknownObjectXml(parser, tagName);
+            name[0] = valueName;
+            return res;
         } else {
-            throw new XmlPullParserException(
-                "Unknown tag: " + tagName);
+            throw new XmlPullParserException("Unknown tag: " + tagName);
         }
 
         // Skip through to end tag.
@@ -967,4 +1424,39 @@
             throws IOException {
         out.attribute(null, name, Boolean.toString(value));
     }
+
+    /** @hide */
+    public interface WriteMapCallback {
+        /**
+         * Called from writeMapXml when an Object type is not recognized. The implementer
+         * must write out the entire element including start and end tags.
+         *
+         * @param v The object to be written out
+         * @param name The mapping key for v. Must be written into the "name" attribute of the
+         *             start tag.
+         * @param out The XML output stream.
+         * @throws XmlPullParserException on unrecognized Object type.
+         * @throws IOException on XmlSerializer serialization errors.
+         * @hide
+         */
+         public void writeUnknownObject(Object v, String name, XmlSerializer out)
+                 throws XmlPullParserException, IOException;
+    }
+
+    /** @hide */
+    public interface ReadMapCallback {
+        /**
+         * Called from readThisMapXml when a START_TAG is not recognized. The input stream
+         * is positioned within the start tag so that attributes can be read using in.getAttribute.
+         *
+         * @param in the XML input stream
+         * @param tag the START_TAG that was not recognized.
+         * @return the Object parsed from the stream which will be put into the map.
+         * @throws XmlPullParserException if the START_TAG is not recognized.
+         * @throws IOException on XmlPullParser serialization errors.
+         * @hide
+         */
+        public Object readThisUnknownObjectXml(XmlPullParser in, String tag)
+                throws XmlPullParserException, IOException;
+    }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 2d72494..f446c3a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -138,6 +138,7 @@
 	android_hardware_Camera.cpp \
 	android_hardware_camera2_CameraMetadata.cpp \
 	android_hardware_camera2_legacy_LegacyCameraDevice.cpp \
+	android_hardware_camera2_DngCreator.cpp \
 	android_hardware_SensorManager.cpp \
 	android_hardware_SerialPort.cpp \
 	android_hardware_UsbDevice.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 2d350e0..0c7eefa 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -80,6 +80,7 @@
 extern int register_android_hardware_Camera(JNIEnv *env);
 extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
 extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env);
+extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
 extern int register_android_hardware_SensorManager(JNIEnv *env);
 extern int register_android_hardware_SerialPort(JNIEnv *env);
 extern int register_android_hardware_UsbDevice(JNIEnv *env);
@@ -1286,6 +1287,7 @@
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_camera2_CameraMetadata),
     REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice),
+    REG_JNI(register_android_hardware_camera2_DngCreator),
     REG_JNI(register_android_hardware_SensorManager),
     REG_JNI(register_android_hardware_SerialPort),
     REG_JNI(register_android_hardware_UsbDevice),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 7aa241a..928a7f8 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -128,8 +128,7 @@
 static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
         int sampleSize, bool ditherImage) {
 
-    SkImageInfo bitmapInfo;
-    if (!bitmap->asImageInfo(&bitmapInfo)) {
+    if (kUnknown_SkColorType == bitmap->colorType()) {
         ALOGW("bitmap has unknown configuration so no memory has been allocated");
         return NULL;
     }
@@ -137,9 +136,9 @@
     SkImageRef* pr;
     // only use ashmem for large images, since mmaps come at a price
     if (bitmap->getSize() >= 32 * 1024) {
-        pr = new SkImageRef_ashmem(bitmapInfo, stream, sampleSize);
+        pr = new SkImageRef_ashmem(bitmap->info(), stream, sampleSize);
     } else {
-        pr = new SkImageRef_GlobalPool(bitmapInfo, stream, sampleSize);
+        pr = new SkImageRef_GlobalPool(bitmap->info(), stream, sampleSize);
     }
     pr->setDitherImage(ditherImage);
     bitmap->setPixelRef(pr)->unref();
diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp
index fbfa2ec..3275875 100644
--- a/core/jni/android/graphics/DrawFilter.cpp
+++ b/core/jni/android/graphics/DrawFilter.cpp
@@ -30,6 +30,35 @@
 
 namespace android {
 
+// Custom version of SkPaintFlagsDrawFilter that also calls setFilterLevel.
+class CompatFlagsDrawFilter : public SkPaintFlagsDrawFilter {
+public:
+    CompatFlagsDrawFilter(uint32_t clearFlags, uint32_t setFlags,
+            SkPaint::FilterLevel desiredLevel)
+    : SkPaintFlagsDrawFilter(clearFlags, setFlags)
+    , fDesiredLevel(desiredLevel) {
+    }
+
+    virtual bool filter(SkPaint* paint, Type type) {
+        SkPaintFlagsDrawFilter::filter(paint, type);
+        paint->setFilterLevel(fDesiredLevel);
+        return true;
+    }
+
+private:
+    const SkPaint::FilterLevel fDesiredLevel;
+};
+
+// Returns whether flags contains FILTER_BITMAP_FLAG. If flags does, remove it.
+static inline bool hadFiltering(jint& flags) {
+    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
+    static const uint32_t sFilterBitmapFlag = 0x02;
+
+    const bool result = (flags & sFilterBitmapFlag) != 0;
+    flags &= ~sFilterBitmapFlag;
+    return result;
+}
+
 class SkDrawFilterGlue {
 public:
 
@@ -40,12 +69,25 @@
 
     static jlong CreatePaintFlagsDF(JNIEnv* env, jobject clazz,
                                     jint clearFlags, jint setFlags) {
-        // trim off any out-of-range bits
-        clearFlags &= SkPaint::kAllFlags;
-        setFlags &= SkPaint::kAllFlags;
-
         if (clearFlags | setFlags) {
-            SkDrawFilter* filter = new SkPaintFlagsDrawFilter(clearFlags, setFlags);
+            // Mask both groups of flags to remove FILTER_BITMAP_FLAG, which no
+            // longer has a Skia equivalent flag (instead it corresponds to
+            // calling setFilterLevel), and keep track of which group(s), if
+            // any, had the flag set.
+            const bool turnFilteringOn = hadFiltering(setFlags);
+            const bool turnFilteringOff = hadFiltering(clearFlags);
+
+            SkDrawFilter* filter;
+            if (turnFilteringOn) {
+                // Turning filtering on overrides turning it off.
+                filter = new CompatFlagsDrawFilter(clearFlags, setFlags,
+                        SkPaint::kLow_FilterLevel);
+            } else if (turnFilteringOff) {
+                filter = new CompatFlagsDrawFilter(clearFlags, setFlags,
+                        SkPaint::kNone_FilterLevel);
+            } else {
+                filter = new SkPaintFlagsDrawFilter(clearFlags, setFlags);
+            }
             return reinterpret_cast<jlong>(filter);
         } else {
             return NULL;
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index fcf8f83e..ddcc396 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -51,6 +51,8 @@
     jfieldID    fifoMaxEventCount;
     jfieldID    stringType;
     jfieldID    requiredPermission;
+    jfieldID    maxDelay;
+    jfieldID    isWakeUpSensor;
 } gSensorOffsets;
 
 
@@ -78,6 +80,8 @@
     sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
     sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
                                                         "Ljava/lang/String;");
+    sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
+    sensorOffsets.isWakeUpSensor = _env->GetFieldID(sensorClass, "mWakeUpSensor",  "Z");
 }
 
 static jint
@@ -112,6 +116,8 @@
     env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
     env->SetObjectField(sensor, sensorOffsets.requiredPermission,
                         requiredPermission);
+    env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
+    env->SetBooleanField(sensor, sensorOffsets.isWakeUpSensor, list->isWakeUpSensor());
     next++;
     return size_t(next) < count ? next : 0;
 }
@@ -160,7 +166,8 @@
         ASensorEvent buffer[16];
         while ((n = q->read(buffer, 16)) > 0) {
             for (int i=0 ; i<n ; i++) {
-                if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
+                if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER ||
+                    buffer[i].type == SENSOR_TYPE_WAKE_UP_STEP_COUNTER) {
                     // step-counter returns a uint64, but the java API only deals with floats
                     float value = float(buffer[i].u64.step_counter);
                     env->SetFloatArrayRegion(mScratch, 0, 1, &value);
@@ -175,11 +182,26 @@
                                         gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
                                         buffer[i].meta_data.sensor);
                 } else {
+                    int8_t status;
+                    switch (buffer[i].type) {
+                    case SENSOR_TYPE_ORIENTATION:
+                    case SENSOR_TYPE_MAGNETIC_FIELD:
+                    case SENSOR_TYPE_ACCELEROMETER:
+                    case SENSOR_TYPE_GYROSCOPE:
+                        status = buffer[i].vector.status;
+                        break;
+                    case SENSOR_TYPE_HEART_RATE:
+                        status = buffer[i].heart_rate.status;
+                        break;
+                    default:
+                        status = SENSOR_STATUS_ACCURACY_HIGH;
+                        break;
+                    }
                     env->CallVoidMethod(mReceiverObject,
                                         gBaseEventQueueClassInfo.dispatchSensorEvent,
                                         buffer[i].sensor,
                                         mScratch,
-                                        buffer[i].vector.status,
+                                        status,
                                         buffer[i].timestamp);
                 }
                 if (env->ExceptionCheck()) {
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 0d2df80..7935329 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -39,6 +39,9 @@
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/ScopedPrimitiveArray.h>
 
+#include <sys/types.h> // for socketpair
+#include <sys/socket.h> // for socketpair
+
 #if defined(LOG_NNDEBUG)
 #if !LOG_NNDEBUG
 #define ALOGVV ALOGV
@@ -351,6 +354,119 @@
     }
 }
 
+struct DumpMetadataParams {
+    int writeFd;
+    const CameraMetadata* metadata;
+};
+
+static void* CameraMetadata_writeMetadataThread(void* arg) {
+    DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
+
+    /*
+     * Write the dumped data, and close the writing side FD.
+     */
+    p->metadata->dump(p->writeFd, /*verbosity*/2);
+
+    if (close(p->writeFd) < 0) {
+        ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
+                __FUNCTION__, errno, strerror(errno));
+    }
+
+    return NULL;
+}
+
+static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
+    ALOGV("%s", __FUNCTION__);
+    CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+    if (metadata == NULL) {
+        return;
+    }
+
+    /*
+     * Create a socket pair for local streaming read/writes.
+     *
+     * The metadata will be dumped into the write side,
+     * and then read back out (and logged) via the read side.
+     */
+
+    int writeFd, readFd;
+    {
+
+        int sv[2];
+        if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
+            jniThrowExceptionFmt(env, "java/io/IOException",
+                    "Failed to create socketpair (errno = %#x, message = '%s')",
+                    errno, strerror(errno));
+            return;
+        }
+        writeFd = sv[0];
+        readFd = sv[1];
+    }
+
+    /*
+     * Create a thread for doing the writing.
+     *
+     * The reading and writing must be concurrent, otherwise
+     * the write will block forever once it exhausts the capped
+     * buffer size (from getsockopt).
+     */
+    pthread_t writeThread;
+    DumpMetadataParams params = {
+        writeFd,
+        metadata
+    };
+
+    {
+        int threadRet = pthread_create(&writeThread, /*attr*/NULL,
+                CameraMetadata_writeMetadataThread, (void*)&params);
+
+        if (threadRet != 0) {
+            close(writeFd);
+
+            jniThrowExceptionFmt(env, "java/io/IOException",
+                    "Failed to create thread for writing (errno = %#x, message = '%s')",
+                    threadRet, strerror(threadRet));
+        }
+    }
+
+    /*
+     * Read out a byte until stream is complete. Write completed lines
+     * to ALOG.
+     */
+    {
+        char out[] = {'\0', '\0'}; // large enough to append as a string
+        String8 logLine;
+
+        // Read one byte at a time! Very slow but avoids complicated \n scanning.
+        ssize_t res;
+        while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
+            if (out[0] == '\n') {
+                ALOGD("%s", logLine.string());
+                logLine.clear();
+            } else {
+                logLine.append(out);
+            }
+        }
+
+        if (res < 0) {
+            jniThrowExceptionFmt(env, "java/io/IOException",
+                    "Failed to read from fd (errno = %#x, message = '%s')",
+                    errno, strerror(errno));
+            //return;
+        } else if (!logLine.isEmpty()) {
+            ALOGD("%s", logLine.string());
+        }
+    }
+
+    int res;
+
+    // Join until thread finishes. Ensures params/metadata is valid until then.
+    if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
+        ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
+                __FUNCTION__, res, strerror(res));
+    }
+}
+
 static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
     ALOGV("%s", __FUNCTION__);
     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
@@ -436,6 +552,9 @@
   { "nativeWriteValues",
     "(I[B)V",
     (void *)CameraMetadata_writeValues },
+  { "nativeDump",
+    "()V",
+    (void *)CameraMetadata_dump },
 // Parcelable interface
   { "nativeReadFromParcel",
     "(Landroid/os/Parcel;)V",
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
new file mode 100644
index 0000000..7b686e7
--- /dev/null
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -0,0 +1,774 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DngCreator_JNI"
+
+#include <system/camera_metadata.h>
+#include <camera/CameraMetadata.h>
+#include <img_utils/DngUtils.h>
+#include <img_utils/TagDefinitions.h>
+#include <img_utils/TiffIfd.h>
+#include <img_utils/TiffWriter.h>
+#include <img_utils/Output.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+#include <cutils/properties.h>
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+using namespace android;
+using namespace img_utils;
+
+#define BAIL_IF_INVALID(expr, jnienv, tagId) \
+    if ((expr) != OK) { \
+        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+                "Invalid metadata for tag %x", tagId); \
+        return; \
+    }
+
+#define BAIL_IF_EMPTY(entry, jnienv, tagId) \
+    if (entry.count == 0) { \
+        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+                "Missing metadata fields for tag %x", tagId); \
+        return; \
+    }
+
+#define ANDROID_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
+
+static struct {
+    jfieldID mNativeContext;
+} gDngCreatorClassInfo;
+
+static struct {
+    jmethodID mWriteMethod;
+} gOutputStreamClassInfo;
+
+enum {
+    BITS_PER_SAMPLE = 16,
+    BYTES_PER_SAMPLE = 2,
+    TIFF_IFD_0 = 0
+};
+
+// ----------------------------------------------------------------------------
+
+// This class is not intended to be used across JNI calls.
+class JniOutputStream : public Output, public LightRefBase<JniOutputStream> {
+public:
+    JniOutputStream(JNIEnv* env, jobject outStream);
+
+    virtual ~JniOutputStream();
+
+    status_t open();
+    status_t write(const uint8_t* buf, size_t offset, size_t count);
+    status_t close();
+private:
+    enum {
+        BYTE_ARRAY_LENGTH = 1024
+    };
+    jobject mOutputStream;
+    JNIEnv* mEnv;
+    jbyteArray mByteArray;
+};
+
+JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
+        mEnv(env) {
+    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
+    if (mByteArray == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
+    }
+}
+
+JniOutputStream::~JniOutputStream() {
+    mEnv->DeleteLocalRef(mByteArray);
+}
+
+status_t JniOutputStream::open() {
+    // Do nothing
+    return OK;
+}
+
+status_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) {
+    while(count > 0) {
+        size_t len = BYTE_ARRAY_LENGTH;
+        len = (count > len) ? len : count;
+        mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset));
+
+        if (mEnv->ExceptionCheck()) {
+            return BAD_VALUE;
+        }
+
+        mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray,
+                0, len);
+
+        if (mEnv->ExceptionCheck()) {
+            return BAD_VALUE;
+        }
+
+        count -= len;
+        offset += len;
+    }
+    return OK;
+}
+
+status_t JniOutputStream::close() {
+    // Do nothing
+    return OK;
+}
+
+// ----------------------------------------------------------------------------
+
+extern "C" {
+
+static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
+    ALOGV("%s:", __FUNCTION__);
+    return reinterpret_cast<TiffWriter*>(env->GetLongField(thiz,
+            gDngCreatorClassInfo.mNativeContext));
+}
+
+static void DngCreator_setCreator(JNIEnv* env, jobject thiz, sp<TiffWriter> writer) {
+    ALOGV("%s:", __FUNCTION__);
+    TiffWriter* current = DngCreator_getCreator(env, thiz);
+    if (writer != NULL) {
+        writer->incStrong((void*) DngCreator_setCreator);
+    }
+    if (current) {
+        current->decStrong((void*) DngCreator_setCreator);
+    }
+    env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext,
+            reinterpret_cast<jlong>(writer.get()));
+}
+
+static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
+    ALOGV("%s:", __FUNCTION__);
+
+    gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz,
+            ANDROID_DNGCREATOR_CTX_JNI_ID, "J");
+    LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL,
+            "can't find android/hardware/camera2/DngCreator.%s",
+            ANDROID_DNGCREATOR_CTX_JNI_ID);
+
+    jclass outputStreamClazz = env->FindClass("java/io/OutputStream");
+    LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class");
+    gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V");
+    LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method");
+}
+
+static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
+        jobject resultsPtr) {
+    ALOGV("%s:", __FUNCTION__);
+    CameraMetadata characteristics;
+    CameraMetadata results;
+    if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) {
+         jniThrowException(env, "java/lang/AssertionError",
+                "No native metadata defined for camera characteristics.");
+         return;
+    }
+    if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) {
+        jniThrowException(env, "java/lang/AssertionError",
+                "No native metadata defined for capture results.");
+        return;
+    }
+
+    sp<TiffWriter> writer = new TiffWriter();
+
+    writer->addIfd(TIFF_IFD_0);
+
+    status_t err = OK;
+
+    const uint32_t samplesPerPixel = 1;
+    const uint32_t bitsPerSample = BITS_PER_SAMPLE;
+    const uint32_t bitsPerByte = BITS_PER_SAMPLE / BYTES_PER_SAMPLE;
+    uint32_t imageWidth = 0;
+    uint32_t imageHeight = 0;
+
+    OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
+
+    // TODO: Greensplit.
+    // TODO: UniqueCameraModel
+    // TODO: Add remaining non-essential tags
+    {
+        // Set orientation
+        uint16_t orientation = 1; // Normal
+        BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
+                TAG_ORIENTATION);
+    }
+
+    {
+        // Set subfiletype
+        uint32_t subfileType = 0; // Main image
+        BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
+                TAG_NEWSUBFILETYPE);
+    }
+
+    {
+        // Set bits per sample
+        uint16_t bits = static_cast<uint16_t>(bitsPerSample);
+        BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
+                TAG_BITSPERSAMPLE);
+    }
+
+    {
+        // Set compression
+        uint16_t compression = 1; // None
+        BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
+                TAG_COMPRESSION);
+    }
+
+    {
+        // Set dimensions
+        camera_metadata_entry entry =
+                characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+        BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH);
+        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
+        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
+        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
+                TAG_IMAGEWIDTH);
+        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
+                TAG_IMAGELENGTH);
+        imageWidth = width;
+        imageHeight = height;
+    }
+
+    {
+        // Set photometric interpretation
+        uint16_t interpretation = 32803;
+        BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
+                TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION);
+    }
+
+    {
+        // Set blacklevel tags
+        camera_metadata_entry entry =
+                characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+        BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL);
+        const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
+        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
+                TAG_BLACKLEVEL);
+
+        uint16_t repeatDim[2] = {2, 2};
+        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
+                TAG_BLACKLEVELREPEATDIM);
+    }
+
+    {
+        // Set samples per pixel
+        uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
+        BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
+                env, TAG_SAMPLESPERPIXEL);
+    }
+
+    {
+        // Set planar configuration
+        uint16_t config = 1; // Chunky
+        BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
+                env, TAG_PLANARCONFIGURATION);
+    }
+
+    {
+        // Set CFA pattern dimensions
+        uint16_t repeatDim[2] = {2, 2};
+        BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
+                env, TAG_CFAREPEATPATTERNDIM);
+    }
+
+    {
+        // Set CFA pattern
+        camera_metadata_entry entry =
+                        characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
+        BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN);
+        camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
+                static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
+                entry.data.u8[0]);
+        switch(cfa) {
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
+                uint8_t cfa[4] = {0, 1, 1, 2};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
+                break;
+            }
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
+                uint8_t cfa[4] = {1, 0, 2, 1};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_GRBG;
+                break;
+            }
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
+                uint8_t cfa[4] = {1, 2, 0, 1};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_GBRG;
+                break;
+            }
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
+                uint8_t cfa[4] = {2, 1, 1, 0};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_BGGR;
+                break;
+            }
+            default: {
+                jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                            "Invalid metadata for tag %d", TAG_CFAPATTERN);
+                return;
+            }
+        }
+    }
+
+    {
+        // Set CFA plane color
+        uint8_t cfaPlaneColor[3] = {0, 1, 2};
+        BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
+                env, TAG_CFAPLANECOLOR);
+    }
+
+    {
+        // Set CFA layout
+        uint16_t cfaLayout = 1;
+        BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
+                env, TAG_CFALAYOUT);
+    }
+
+    {
+        // Set DNG version information
+        uint8_t version[4] = {1, 4, 0, 0};
+        BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
+                env, TAG_DNGVERSION);
+
+        uint8_t backwardVersion[4] = {1, 1, 0, 0};
+        BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
+                env, TAG_DNGBACKWARDVERSION);
+    }
+
+    {
+        // Set whitelevel
+        camera_metadata_entry entry =
+                characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
+        BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL);
+        uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
+        BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
+                TAG_WHITELEVEL);
+    }
+
+    {
+        // Set default scale
+        uint32_t defaultScale[4] = {1, 1, 1, 1};
+        BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
+                env, TAG_DEFAULTSCALE);
+    }
+
+    bool singleIlluminant = false;
+    {
+        // Set calibration illuminants
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
+        BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1);
+        camera_metadata_entry entry2 =
+            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
+        if (entry2.count == 0) {
+            singleIlluminant = true;
+        }
+        uint16_t ref1 = entry1.data.u8[0];
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
+                TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1);
+
+        if (!singleIlluminant) {
+            uint16_t ref2 = entry2.data.u8[0];
+            BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
+                    TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2);
+        }
+    }
+
+    {
+        // Set color transforms
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
+        BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1);
+
+        int32_t colorTransform1[entry1.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry1.count; ++i) {
+            colorTransform1[ctr++] = entry1.data.r[i].numerator;
+            colorTransform1[ctr++] = entry1.data.r[i].denominator;
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1, TIFF_IFD_0),
+                env, TAG_COLORMATRIX1);
+
+        if (!singleIlluminant) {
+            camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
+            BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2);
+            int32_t colorTransform2[entry2.count * 2];
+
+            ctr = 0;
+            for(size_t i = 0; i < entry2.count; ++i) {
+                colorTransform2[ctr++] = entry2.data.r[i].numerator;
+                colorTransform2[ctr++] = entry2.data.r[i].denominator;
+            }
+
+            BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2, TIFF_IFD_0),
+                    env, TAG_COLORMATRIX2);
+        }
+    }
+
+    {
+        // Set calibration transforms
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
+        BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1);
+
+        int32_t calibrationTransform1[entry1.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry1.count; ++i) {
+            calibrationTransform1[ctr++] = entry1.data.r[i].numerator;
+            calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1,
+                TIFF_IFD_0), env, TAG_CAMERACALIBRATION1);
+
+        if (!singleIlluminant) {
+            camera_metadata_entry entry2 =
+                characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
+            BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2);
+            int32_t calibrationTransform2[entry2.count * 2];
+
+            ctr = 0;
+            for(size_t i = 0; i < entry2.count; ++i) {
+                calibrationTransform2[ctr++] = entry2.data.r[i].numerator;
+                calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
+            }
+
+            BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1,
+                    TIFF_IFD_0),  env, TAG_CAMERACALIBRATION2);
+        }
+    }
+
+    {
+        // Set forward transforms
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
+        BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1);
+
+        int32_t forwardTransform1[entry1.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry1.count; ++i) {
+            forwardTransform1[ctr++] = entry1.data.r[i].numerator;
+            forwardTransform1[ctr++] = entry1.data.r[i].denominator;
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
+                TIFF_IFD_0), env, TAG_FORWARDMATRIX1);
+
+        if (!singleIlluminant) {
+            camera_metadata_entry entry2 =
+                characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
+            BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2);
+            int32_t forwardTransform2[entry2.count * 2];
+
+            ctr = 0;
+            for(size_t i = 0; i < entry2.count; ++i) {
+                forwardTransform2[ctr++] = entry2.data.r[i].numerator;
+                forwardTransform2[ctr++] = entry2.data.r[i].denominator;
+            }
+
+            BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
+                    TIFF_IFD_0),  env, TAG_FORWARDMATRIX2);
+        }
+    }
+
+    {
+        // Set camera neutral
+        camera_metadata_entry entry =
+            results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
+        BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL);
+        uint32_t cameraNeutral[entry.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry.count; ++i) {
+            cameraNeutral[ctr++] =
+                    static_cast<uint32_t>(entry.data.r[i].numerator);
+            cameraNeutral[ctr++] =
+                    static_cast<uint32_t>(entry.data.r[i].denominator);
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
+                TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL);
+    }
+
+    {
+        // Setup data strips
+        // TODO: Switch to tiled implementation.
+        uint32_t offset = 0;
+        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &offset, TIFF_IFD_0), env,
+                TAG_STRIPOFFSETS);
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_ROWSPERSTRIP, 1, &imageHeight, TIFF_IFD_0), env,
+                TAG_ROWSPERSTRIP);
+
+        uint32_t byteCount = imageWidth * imageHeight * bitsPerSample * samplesPerPixel /
+                bitsPerByte;
+        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPBYTECOUNTS, 1, &byteCount, TIFF_IFD_0), env,
+                TAG_STRIPBYTECOUNTS);
+    }
+
+    {
+        // Setup default crop + crop origin tags
+        uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
+        uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
+        if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
+            uint32_t defaultCropOrigin[] = {margin, margin};
+            uint32_t defaultCropSize[] = {imageWidth - margin, imageHeight - margin};
+            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
+                    TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN);
+            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
+                    TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE);
+        }
+    }
+
+    {
+        // Setup unique camera model tag
+        char model[PROPERTY_VALUE_MAX];
+        property_get("ro.product.model", model, "");
+
+        char manufacturer[PROPERTY_VALUE_MAX];
+        property_get("ro.product.manufacturer", manufacturer, "");
+
+        char brand[PROPERTY_VALUE_MAX];
+        property_get("ro.product.brand", brand, "");
+
+        String8 cameraModel(model);
+        cameraModel += "-";
+        cameraModel += manufacturer;
+        cameraModel += "-";
+        cameraModel += brand;
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
+                reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
+                TAG_UNIQUECAMERAMODEL);
+    }
+
+    {
+        // Setup opcode List 2
+        camera_metadata_entry entry1 =
+                characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+        BAIL_IF_EMPTY(entry1, env, TAG_OPCODELIST2);
+        uint32_t lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]);
+        uint32_t lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]);
+
+        camera_metadata_entry entry2 =
+                results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+        BAIL_IF_EMPTY(entry2, env, TAG_OPCODELIST2);
+        if (entry2.count == lsmWidth * lsmHeight * 4) {
+
+            OpcodeListBuilder builder;
+            status_t err = builder.addGainMapsForMetadata(lsmWidth,
+                                                          lsmHeight,
+                                                          0,
+                                                          0,
+                                                          imageHeight,
+                                                          imageWidth,
+                                                          opcodeCfaLayout,
+                                                          entry2.data.f);
+            if (err == OK) {
+                size_t listSize = builder.getSize();
+                uint8_t opcodeListBuf[listSize];
+                err = builder.buildOpList(opcodeListBuf);
+                if (err == OK) {
+                    BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
+                            TIFF_IFD_0), env, TAG_OPCODELIST2);
+                } else {
+                    ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__);
+                    jniThrowRuntimeException(env, "failed to construct lens shading map opcode.");
+                }
+            } else {
+                ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
+                jniThrowRuntimeException(env, "failed to add lens shading map.");
+            }
+        } else {
+            ALOGW("%s: Lens shading map not present in results, skipping...", __FUNCTION__);
+        }
+    }
+
+    DngCreator_setCreator(env, thiz, writer);
+}
+
+static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
+    ALOGV("%s:", __FUNCTION__);
+    DngCreator_setCreator(env, thiz, NULL);
+}
+
+static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeSetOrientation is not implemented");
+}
+
+static void DngCreator_nativeSetThumbnailBitmap(JNIEnv* env, jobject thiz, jobject bitmap) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeSetThumbnailBitmap is not implemented");
+}
+
+static void DngCreator_nativeSetThumbnailImage(JNIEnv* env, jobject thiz, jint width, jint height,
+        jobject yBuffer, jint yRowStride, jint yPixStride, jobject uBuffer, jint uRowStride,
+        jint uPixStride, jobject vBuffer, jint vRowStride, jint vPixStride) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeSetThumbnailImage is not implemented");
+}
+
+static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width,
+        jint height, jobject inBuffer, jint rowStride, jint pixStride) {
+    ALOGV("%s:", __FUNCTION__);
+
+    sp<JniOutputStream> out = new JniOutputStream(env, outStream);
+    if(env->ExceptionCheck()) {
+        ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
+        return;
+    }
+
+    uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
+    if (pixelBytes == NULL) {
+        ALOGE("%s: Could not get native byte buffer", __FUNCTION__);
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid bytebuffer");
+        return;
+    }
+
+    TiffWriter* writer = DngCreator_getCreator(env, thiz);
+    if (writer == NULL) {
+        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+        jniThrowException(env, "java/lang/AssertionError",
+                "Write called with uninitialized DngCreator");
+        return;
+    }
+    // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
+    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, TIFF_IFD_0)->getData<uint32_t>());
+    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, TIFF_IFD_0)->getData<uint32_t>());
+    if (metadataWidth != width) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
+                        "Metadata width %d doesn't match image width %d", metadataWidth, width);
+        return;
+    }
+
+    if (metadataHeight != height) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
+                        "Metadata height %d doesn't match image height %d", metadataHeight, height);
+        return;
+    }
+
+    uint32_t stripOffset = writer->getTotalSize();
+
+    BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &stripOffset, TIFF_IFD_0), env,
+                    TAG_STRIPOFFSETS);
+
+    if (writer->write(out.get()) != OK) {
+        if (!env->ExceptionCheck()) {
+            jniThrowException(env, "java/io/IOException", "Failed to write metadata");
+        }
+        return;
+    }
+
+    size_t fullSize = rowStride * height;
+    jlong capacity = env->GetDirectBufferCapacity(inBuffer);
+    if (capacity < 0 || fullSize > capacity) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                "Invalid size %d for Image, size given in metadata is %d at current stride",
+                capacity, fullSize);
+        return;
+    }
+
+    if (pixStride == BYTES_PER_SAMPLE && rowStride == width * BYTES_PER_SAMPLE) {
+        if (out->write(pixelBytes, 0, fullSize) != OK || env->ExceptionCheck()) {
+            if (!env->ExceptionCheck()) {
+                jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+            }
+            return;
+        }
+    } else if (pixStride == BYTES_PER_SAMPLE) {
+        for (size_t i = 0; i < height; ++i) {
+            if (out->write(pixelBytes, i * rowStride, pixStride * width) != OK ||
+                        env->ExceptionCheck()) {
+                if (!env->ExceptionCheck()) {
+                    jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+                }
+                return;
+            }
+        }
+    } else {
+        for (size_t i = 0; i < height; ++i) {
+            for (size_t j = 0; j < width; ++j) {
+                if (out->write(pixelBytes, i * rowStride + j * pixStride,
+                        BYTES_PER_SAMPLE) != OK || !env->ExceptionCheck()) {
+                    if (env->ExceptionCheck()) {
+                        jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+                    }
+                    return;
+                }
+            }
+        }
+    }
+
+}
+
+static void DngCreator_nativeWriteByteBuffer(JNIEnv* env, jobject thiz, jobject outStream,
+        jobject rawBuffer, jlong offset) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeWriteByteBuffer is not implemented.");
+}
+
+static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream,
+        jobject inStream, jlong offset) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeWriteInputStream is not implemented.");
+}
+
+} /*extern "C" */
+
+static JNINativeMethod gDngCreatorMethods[] = {
+    {"nativeClassInit",        "()V", (void*) DngCreator_nativeClassInit},
+    {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
+            "Landroid/hardware/camera2/impl/CameraMetadataNative;)V", (void*) DngCreator_init},
+    {"nativeDestroy",           "()V",      (void*) DngCreator_destroy},
+    {"nativeSetOrientation",    "(I)V",     (void*) DngCreator_nativeSetOrientation},
+    {"nativeSetThumbnailBitmap","(Landroid/graphics/Bitmap;)V",
+            (void*) DngCreator_nativeSetThumbnailBitmap},
+    {"nativeSetThumbnailImage",
+            "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)V",
+            (void*) DngCreator_nativeSetThumbnailImage},
+    {"nativeWriteImage",        "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;II)V",
+            (void*) DngCreator_nativeWriteImage},
+    {"nativeWriteByteBuffer",    "(Ljava/io/OutputStream;Ljava/nio/ByteBuffer;J)V",
+            (void*) DngCreator_nativeWriteByteBuffer},
+    {"nativeWriteInputStream",    "(Ljava/io/OutputStream;Ljava/io/InputStream;J)V",
+            (void*) DngCreator_nativeWriteInputStream},
+};
+
+int register_android_hardware_camera2_DngCreator(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+                   "android/hardware/camera2/DngCreator", gDngCreatorMethods,
+                   NELEM(gDngCreatorMethods));
+}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 48fb729..6f256f0 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -293,12 +293,24 @@
     proxy->destroyLayer(layer);
 }
 
+static void android_view_ThreadedRenderer_flushCaches(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jint flushMode) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->flushCaches(static_cast<Caches::FlushMode>(flushMode));
+}
+
 static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->fence();
 }
 
+static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->notifyFramePending();
+}
+
 #endif
 
 // ----------------------------------------------------------------------------
@@ -328,7 +340,9 @@
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
     { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
     { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer },
+    { "nFlushCaches", "(JI)V", (void*) android_view_ThreadedRenderer_flushCaches },
     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
+    { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
 #endif
 };
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1874fd8..14141d7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1014,6 +1014,13 @@
         android:description="@string/permdesc_sim_communication"
         android:protectionLevel="dangerous" />
 
+    <!-- Allows TvInputService to access underlying TV input hardware such as
+         built-in tuners and HDMI-in's.
+         @hide This should only be used by OEM's TvInputService's.
+    -->
+    <permission android:name="android.permission.TV_INPUT_HARDWARE"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- =========================================== -->
     <!-- Permissions associated with audio capture -->
     <!-- =========================================== -->
diff --git a/core/res/res/anim/slide_in_micro.xml b/core/res/res/anim/slide_in_micro.xml
new file mode 100644
index 0000000..6320e80
--- /dev/null
+++ b/core/res/res/anim/slide_in_micro.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/slide_in_micro.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate android:fromXDelta="100%p" android:toXDelta="0"
+               android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+           android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+           android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
new file mode 100644
index 0000000..4cb6df0
--- /dev/null
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/slide_out_micro.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate android:fromXDelta="0" android:toXDelta="100%p"
+               android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+           android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+           android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
deleted file mode 100644
index 1880a15..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
deleted file mode 100644
index aecb4d2..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
deleted file mode 100644
index 8401f91..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
deleted file mode 100644
index 5832865..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
deleted file mode 100644
index 6d14962..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
deleted file mode 100644
index aee057c..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
deleted file mode 100644
index fb5801e..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
deleted file mode 100644
index fdb5271..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
deleted file mode 100644
index b8c7397..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
deleted file mode 100644
index d0395a8..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
deleted file mode 100644
index 59bb437..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
deleted file mode 100644
index c053b90..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
deleted file mode 100644
index eb30a79..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
deleted file mode 100644
index 1af0bff..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
deleted file mode 100644
index 3b36e7d..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
deleted file mode 100644
index c12d20a..0000000
--- a/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_off_qntm_alpha.png
deleted file mode 100644
index 5bc1d90..0000000
--- a/core/res/res/drawable-hdpi/btn_check_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_on_qntm_alpha.png
deleted file mode 100644
index e5de2c1..0000000
--- a/core/res/res/drawable-hdpi/btn_check_on_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png
new file mode 100644
index 0000000..3cb4073
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png
new file mode 100644
index 0000000..8fd1480
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png
new file mode 100644
index 0000000..d35b579
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png
new file mode 100644
index 0000000..543c6bc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png
new file mode 100644
index 0000000..4fc3c40
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png
new file mode 100644
index 0000000..c184535
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png
new file mode 100644
index 0000000..9f9dd43
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png
new file mode 100644
index 0000000..8c629ce
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png
new file mode 100644
index 0000000..81134b5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png
new file mode 100644
index 0000000..baa5860
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png
new file mode 100644
index 0000000..d7e28366
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png
new file mode 100644
index 0000000..6f24795
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png
new file mode 100644
index 0000000..22f997d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png
new file mode 100644
index 0000000..85f4471
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png
new file mode 100644
index 0000000..ad483c9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png
new file mode 100644
index 0000000..f24c2fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png
new file mode 100644
index 0000000..7a9e9bd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png
new file mode 100644
index 0000000..af04902
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png
new file mode 100644
index 0000000..32a6e94
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png
new file mode 100644
index 0000000..c1b4b37
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png
new file mode 100644
index 0000000..34d3ade
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png
new file mode 100644
index 0000000..3d5db53
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png
new file mode 100644
index 0000000..ea35437
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png
new file mode 100644
index 0000000..48744f8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png
new file mode 100644
index 0000000..f654517
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png
new file mode 100644
index 0000000..16f959a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png
new file mode 100644
index 0000000..98c754b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png
new file mode 100644
index 0000000..5827dc2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png
new file mode 100644
index 0000000..9850d74
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png
new file mode 100644
index 0000000..03ab06b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png
new file mode 100644
index 0000000..11cdd88
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png
new file mode 100644
index 0000000..874edbf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
deleted file mode 100644
index 882365b..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
deleted file mode 100644
index f6c7094..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
deleted file mode 100644
index 0e326c9..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
deleted file mode 100644
index 8bf1170..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
deleted file mode 100644
index cedb66e..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
deleted file mode 100644
index 257d7ba..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
deleted file mode 100644
index e07b36e..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
deleted file mode 100644
index ef94200..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
deleted file mode 100644
index ad67004..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
deleted file mode 100644
index 50796e2..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
deleted file mode 100644
index ba7be9e..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
deleted file mode 100644
index bdbfe78..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
deleted file mode 100644
index fe89951..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
deleted file mode 100644
index 840c88f..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
deleted file mode 100644
index 621d1d2..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
deleted file mode 100644
index fd8be89..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_qntm_alpha.png
deleted file mode 100644
index 7bef530..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_off_qntm_alpha.png
deleted file mode 100644
index ae50dd5..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_qntm_alpha.png
deleted file mode 100644
index 0678dbb..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_on_qntm_alpha.png
deleted file mode 100644
index f332925..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_on_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png
new file mode 100644
index 0000000..da88e98
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png
new file mode 100644
index 0000000..907d92d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png
new file mode 100644
index 0000000..9d24dc1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png
new file mode 100644
index 0000000..8aa2605
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png
new file mode 100644
index 0000000..b4cdf02
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png
new file mode 100644
index 0000000..0724ed7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png
new file mode 100644
index 0000000..c9bd4e3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png
new file mode 100644
index 0000000..5630ec3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png
new file mode 100644
index 0000000..4bf666c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png
new file mode 100644
index 0000000..dffaa07
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png
new file mode 100644
index 0000000..5f86e18
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png
new file mode 100644
index 0000000..9b50aef
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png
new file mode 100644
index 0000000..1cf5e7f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png
new file mode 100644
index 0000000..2bb641a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png
new file mode 100644
index 0000000..08e7485
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png
new file mode 100644
index 0000000..519b5a3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png
new file mode 100644
index 0000000..0d3e1e7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png
new file mode 100644
index 0000000..88c4a9e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png
new file mode 100644
index 0000000..8fa2e88
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png
new file mode 100644
index 0000000..53dd9d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png
new file mode 100644
index 0000000..e235195
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png
new file mode 100644
index 0000000..1721284
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png
new file mode 100644
index 0000000..31819fa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png
new file mode 100644
index 0000000..5de44b9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png
new file mode 100644
index 0000000..aa20f65
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png
new file mode 100644
index 0000000..c379ba7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png
new file mode 100644
index 0000000..e23b410
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png
new file mode 100644
index 0000000..a9543dc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png
new file mode 100644
index 0000000..2473b78
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png
new file mode 100644
index 0000000..b4acc9c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png
new file mode 100644
index 0000000..c9cf344
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png
new file mode 100644
index 0000000..a8c390e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png
new file mode 100644
index 0000000..c54f8d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png
new file mode 100644
index 0000000..e062f61
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png
new file mode 100644
index 0000000..7737646
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png
new file mode 100644
index 0000000..65ff45e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png
new file mode 100644
index 0000000..11aaec0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png
new file mode 100644
index 0000000..9e1b60f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png
new file mode 100644
index 0000000..1e45687
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png
new file mode 100644
index 0000000..1e45687
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png
new file mode 100644
index 0000000..6c48456
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png
new file mode 100644
index 0000000..a4d084b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png
new file mode 100644
index 0000000..1e1a1b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png
new file mode 100644
index 0000000..1e1a1b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png
new file mode 100644
index 0000000..1e1a1b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png
new file mode 100644
index 0000000..1e1a1b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png
new file mode 100644
index 0000000..1e1a1b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png
new file mode 100644
index 0000000..cf09f97
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png
new file mode 100644
index 0000000..3218e66
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png
new file mode 100644
index 0000000..0acff03
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png
new file mode 100644
index 0000000..c93adf4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png
new file mode 100644
index 0000000..5d8ddc96
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png
new file mode 100644
index 0000000..47206a4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png
new file mode 100644
index 0000000..7d6a91f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png
new file mode 100644
index 0000000..e062f61
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png
new file mode 100644
index 0000000..b0f0dde
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png
new file mode 100644
index 0000000..c54f8d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png
new file mode 100644
index 0000000..c54f8d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png
new file mode 100644
index 0000000..c54f8d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png
new file mode 100644
index 0000000..c54f8d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png
new file mode 100644
index 0000000..c54f8d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png
new file mode 100644
index 0000000..c54f8d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png
new file mode 100644
index 0000000..68e17ad
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png
new file mode 100644
index 0000000..879d9c2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png
new file mode 100644
index 0000000..281923e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png
new file mode 100644
index 0000000..e91d4fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png
new file mode 100644
index 0000000..15baded
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png
new file mode 100644
index 0000000..3d5899f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png
new file mode 100644
index 0000000..e2277bd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png
new file mode 100644
index 0000000..b502e22
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png
new file mode 100644
index 0000000..a70be2c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png
new file mode 100644
index 0000000..9442316
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png
new file mode 100644
index 0000000..33db4a88
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png
new file mode 100644
index 0000000..4e1cd16
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png
new file mode 100644
index 0000000..d5254f4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png
new file mode 100644
index 0000000..7aa0a3e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
deleted file mode 100644
index 73e8f1c..0000000
--- a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
deleted file mode 100644
index ff6affe..0000000
--- a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png
index b11de9e..ac1fc23 100644
--- a/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png
+++ b/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png
index 598b98c..9cdc25b 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png
index 79fe7c5..276d480 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
deleted file mode 100644
index 0f44ff9..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
deleted file mode 100644
index 9d5dda0..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
deleted file mode 100644
index e4ce802..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
deleted file mode 100644
index d1806ac..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
deleted file mode 100644
index ab9315b..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
deleted file mode 100644
index 46e90e6..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
deleted file mode 100644
index e8c56ff..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
deleted file mode 100644
index 59dcb7e..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
deleted file mode 100644
index e9bd4a2..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
deleted file mode 100644
index 1d05037..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
deleted file mode 100644
index 91b40de..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
deleted file mode 100644
index c531cab..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
deleted file mode 100644
index 11bb387..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
deleted file mode 100644
index 8843210..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
deleted file mode 100644
index 6ff2f3d..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
deleted file mode 100644
index a03c1e2..0000000
--- a/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_off_qntm_alpha.png
deleted file mode 100644
index 2ab6b7f..0000000
--- a/core/res/res/drawable-mdpi/btn_check_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_on_qntm_alpha.png
deleted file mode 100644
index 2211d83..0000000
--- a/core/res/res/drawable-mdpi/btn_check_on_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png
new file mode 100644
index 0000000..9759818
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png
new file mode 100644
index 0000000..4eb2c4f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png
new file mode 100644
index 0000000..e6d6b42
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png
new file mode 100644
index 0000000..03cb23a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png
new file mode 100644
index 0000000..bfe3c3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png
new file mode 100644
index 0000000..65bdf42
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png
new file mode 100644
index 0000000..44f9614b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png
new file mode 100644
index 0000000..cf8ec38
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png
new file mode 100644
index 0000000..4d624b3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png
new file mode 100644
index 0000000..7c4eb7f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png
new file mode 100644
index 0000000..e90dd31
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png
new file mode 100644
index 0000000..831c0e8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png
new file mode 100644
index 0000000..7355dfd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png
new file mode 100644
index 0000000..be71a69
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png
new file mode 100644
index 0000000..a4a185b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png
new file mode 100644
index 0000000..8d0386f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png
new file mode 100644
index 0000000..70793c4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png
new file mode 100644
index 0000000..632082b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png
new file mode 100644
index 0000000..e7fc5fb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png
new file mode 100644
index 0000000..91a0a33
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png
new file mode 100644
index 0000000..3bd90d6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png
new file mode 100644
index 0000000..5ac39ec
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png
new file mode 100644
index 0000000..4181983
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png
new file mode 100644
index 0000000..c8b04df
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png
new file mode 100644
index 0000000..b7b3a9f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png
new file mode 100644
index 0000000..62bc4ed
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png
new file mode 100644
index 0000000..ac463ad
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png
new file mode 100644
index 0000000..12b605d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png
new file mode 100644
index 0000000..63a3c6a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png
new file mode 100644
index 0000000..17660c4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png
new file mode 100644
index 0000000..7d9de3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png
new file mode 100644
index 0000000..8aa1be2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
deleted file mode 100644
index 0a22e1a..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
deleted file mode 100644
index 2e2469c..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
deleted file mode 100644
index c1054d9..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
deleted file mode 100644
index cf8d80a..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
deleted file mode 100644
index 9d9e870..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
deleted file mode 100644
index 1bad701..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
deleted file mode 100644
index a84a54f..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
deleted file mode 100644
index 4d8050b..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
deleted file mode 100644
index 374172c..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
deleted file mode 100644
index 233036e..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
deleted file mode 100644
index 61d9b58..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
deleted file mode 100644
index 274e983..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
deleted file mode 100644
index acf16e5..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
deleted file mode 100644
index ee48241..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
deleted file mode 100644
index dbbb736..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
deleted file mode 100644
index bcabd0d..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_qntm_alpha.png
deleted file mode 100644
index 713fee8..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_off_qntm_alpha.png
deleted file mode 100644
index dcb90d0..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png
new file mode 100644
index 0000000..a2b7fce
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png
new file mode 100644
index 0000000..fe0d3b1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png
new file mode 100644
index 0000000..d66d00d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png
new file mode 100644
index 0000000..2f2f5cd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png
new file mode 100644
index 0000000..72c9495
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png
new file mode 100644
index 0000000..7d9090f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png
new file mode 100644
index 0000000..c5442e8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png
new file mode 100644
index 0000000..ca80cdb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png
new file mode 100644
index 0000000..d41a10b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png
new file mode 100644
index 0000000..262c838
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png
new file mode 100644
index 0000000..7f6ea8ba
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png
new file mode 100644
index 0000000..8d50a81
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png
new file mode 100644
index 0000000..0725a68
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png
new file mode 100644
index 0000000..6191a4b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png
new file mode 100644
index 0000000..1904d74
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png
new file mode 100644
index 0000000..bec8dda
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png
new file mode 100644
index 0000000..54ef480
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png
new file mode 100644
index 0000000..55c5163
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png
new file mode 100644
index 0000000..0fe2a897
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png
new file mode 100644
index 0000000..86efab7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png
new file mode 100644
index 0000000..c0a5ca5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png
new file mode 100644
index 0000000..ec55175
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png
new file mode 100644
index 0000000..3e4a690
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png
new file mode 100644
index 0000000..da49734
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png
new file mode 100644
index 0000000..471cda1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png
new file mode 100644
index 0000000..d560262
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png
new file mode 100644
index 0000000..f6096b4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png
new file mode 100644
index 0000000..9e2500b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png
new file mode 100644
index 0000000..efbac99
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png
new file mode 100644
index 0000000..676f0ca
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png
new file mode 100644
index 0000000..4803157
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png
new file mode 100644
index 0000000..4f8a162
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png
new file mode 100644
index 0000000..8c3f26c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png
new file mode 100644
index 0000000..3617168
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png
new file mode 100644
index 0000000..e4366f4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png
new file mode 100644
index 0000000..ea4533b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png
new file mode 100644
index 0000000..94aedbb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png
new file mode 100644
index 0000000..ef84578
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png
new file mode 100644
index 0000000..4de2321
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png
new file mode 100644
index 0000000..4de2321
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png
new file mode 100644
index 0000000..d62fbd5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png
new file mode 100644
index 0000000..3d87c4e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png
new file mode 100644
index 0000000..536ed46
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png
new file mode 100644
index 0000000..536ed46
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png
new file mode 100644
index 0000000..536ed46
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png
new file mode 100644
index 0000000..536ed46
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png
new file mode 100644
index 0000000..536ed46
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png
new file mode 100644
index 0000000..f5b660d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png
new file mode 100644
index 0000000..9e4db6c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png
new file mode 100644
index 0000000..7de2128
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png
new file mode 100644
index 0000000..1980c2c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png
new file mode 100644
index 0000000..6e73ef0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png
new file mode 100644
index 0000000..f897392
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png
new file mode 100644
index 0000000..74a6ebd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png
new file mode 100644
index 0000000..3617168
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png
new file mode 100644
index 0000000..884eb66
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png
new file mode 100644
index 0000000..8c3f26c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png
new file mode 100644
index 0000000..8c3f26c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png
new file mode 100644
index 0000000..8c3f26c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png
new file mode 100644
index 0000000..8c3f26c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png
new file mode 100644
index 0000000..8c3f26c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png
new file mode 100644
index 0000000..8c3f26c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png
new file mode 100644
index 0000000..e5bface
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png
new file mode 100644
index 0000000..dca86ea
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png
new file mode 100644
index 0000000..377a6b4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png
new file mode 100644
index 0000000..0859f62
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png
new file mode 100644
index 0000000..bf5cdcd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png
new file mode 100644
index 0000000..4cd177d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png
new file mode 100644
index 0000000..dfe39ca
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png
new file mode 100644
index 0000000..5d3ab99
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png
new file mode 100644
index 0000000..80922eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png
new file mode 100644
index 0000000..aa77044
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png
new file mode 100644
index 0000000..7b099db
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png
new file mode 100644
index 0000000..088c86a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png
new file mode 100644
index 0000000..3c6b9bc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png
new file mode 100644
index 0000000..adf5100
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
deleted file mode 100644
index 8949b52..0000000
--- a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
deleted file mode 100644
index d727683..0000000
--- a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png
index 8991421..b6538e4 100644
--- a/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png
+++ b/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png
index 506a186..95c0168 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png
index fb0e926..569332a 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
deleted file mode 100644
index 25500e8..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
deleted file mode 100644
index b136e25..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
deleted file mode 100644
index 6a94e30..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
deleted file mode 100644
index d386421..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
deleted file mode 100644
index c811385..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
deleted file mode 100644
index 58b3267..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
deleted file mode 100644
index 0659e72..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
deleted file mode 100644
index b4227d1..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
deleted file mode 100644
index 714ef00..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
deleted file mode 100644
index 139595b..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
deleted file mode 100644
index 4491107..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
deleted file mode 100644
index 20eb752..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
deleted file mode 100644
index 532c9f2..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
deleted file mode 100644
index 0d78a32..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
deleted file mode 100644
index af29678..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
deleted file mode 100644
index 23eb9e3..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_off_qntm_alpha.png
deleted file mode 100644
index 5d820ae..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_on_qntm_alpha.png
deleted file mode 100644
index 019c92e..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_on_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png
new file mode 100644
index 0000000..2347643
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png
new file mode 100644
index 0000000..70aaa01
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png
new file mode 100644
index 0000000..01e498a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png
new file mode 100644
index 0000000..71d1cf7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png
new file mode 100644
index 0000000..d1e7b1d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png
new file mode 100644
index 0000000..7db7d06
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png
new file mode 100644
index 0000000..dadb62e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png
new file mode 100644
index 0000000..f87f744
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png
new file mode 100644
index 0000000..be99d87
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png
new file mode 100644
index 0000000..f83bc05
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png
new file mode 100644
index 0000000..870071d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png
new file mode 100644
index 0000000..3a18414
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png
new file mode 100644
index 0000000..f3d1187
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png
new file mode 100644
index 0000000..4078cca
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png
new file mode 100644
index 0000000..d4849b5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png
new file mode 100644
index 0000000..6e2af72
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png
new file mode 100644
index 0000000..9244174
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png
new file mode 100644
index 0000000..8c7fe95
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png
new file mode 100644
index 0000000..71eb1d0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png
new file mode 100644
index 0000000..613f38a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png
new file mode 100644
index 0000000..2d20ccc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png
new file mode 100644
index 0000000..407f78d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png
new file mode 100644
index 0000000..1bf24b0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png
new file mode 100644
index 0000000..a450bd0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png
new file mode 100644
index 0000000..63ba593
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png
new file mode 100644
index 0000000..6d05e5a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png
new file mode 100644
index 0000000..1c8cd8f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png
new file mode 100644
index 0000000..b8bc564
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png
new file mode 100644
index 0000000..3d80128
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png
new file mode 100644
index 0000000..c21dfba
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png
new file mode 100644
index 0000000..2dfe90d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png
new file mode 100644
index 0000000..5f40d73
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
deleted file mode 100644
index cd11e14..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
deleted file mode 100644
index b10db83..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
deleted file mode 100644
index efeb6fb..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
deleted file mode 100644
index 83080af..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
deleted file mode 100644
index b9cc322..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
deleted file mode 100644
index 3b5f9c4..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
deleted file mode 100644
index 58c93db..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
deleted file mode 100644
index 0f1d010..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
deleted file mode 100644
index 05a7a0f..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
deleted file mode 100644
index 9345035..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
deleted file mode 100644
index 5f149b7..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
deleted file mode 100644
index 191f369..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
deleted file mode 100644
index 44e08e6..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
deleted file mode 100644
index 5a9dfa0..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
deleted file mode 100644
index ee921c6..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
deleted file mode 100644
index 567bb0c..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_qntm_alpha.png
deleted file mode 100644
index 2fd964e..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_off_qntm_alpha.png
deleted file mode 100644
index 8873cd6..0000000
--- a/core/res/res/drawable-xhdpi/btn_radio_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png
new file mode 100644
index 0000000..b54c6ff
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png
new file mode 100644
index 0000000..fff7056
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png
new file mode 100644
index 0000000..026462d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png
new file mode 100644
index 0000000..26cc8de
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png
new file mode 100644
index 0000000..c055fff
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png
new file mode 100644
index 0000000..a22e780
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png
new file mode 100644
index 0000000..357374c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png
new file mode 100644
index 0000000..71d4667
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png
new file mode 100644
index 0000000..2ed175e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png
new file mode 100644
index 0000000..e0f7d8e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png
new file mode 100644
index 0000000..62b0578
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png
new file mode 100644
index 0000000..4d6ef4a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png
new file mode 100644
index 0000000..37cee2d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png
new file mode 100644
index 0000000..a8bc25f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png
new file mode 100644
index 0000000..cf68d93
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png
new file mode 100644
index 0000000..96834bc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png
new file mode 100644
index 0000000..d068dbe
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png
new file mode 100644
index 0000000..4aabb1e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png
new file mode 100644
index 0000000..bbac8e4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png
new file mode 100644
index 0000000..2fc7459
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png
new file mode 100644
index 0000000..83c6d0e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png
new file mode 100644
index 0000000..45c08d7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png
new file mode 100644
index 0000000..05b7dfb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png
new file mode 100644
index 0000000..baf9964
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png
new file mode 100644
index 0000000..d6e0369
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png
new file mode 100644
index 0000000..3f35270
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png
new file mode 100644
index 0000000..a5b34dc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png
new file mode 100644
index 0000000..361967b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png
new file mode 100644
index 0000000..c478bb7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png
new file mode 100644
index 0000000..075fa0c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png
new file mode 100644
index 0000000..d9e364b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png
new file mode 100644
index 0000000..9924496
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png
new file mode 100644
index 0000000..2494fd4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png
new file mode 100644
index 0000000..7bd99fe
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png
new file mode 100644
index 0000000..2ef623b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png
new file mode 100644
index 0000000..19db3e0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png
new file mode 100644
index 0000000..984c3c5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png
new file mode 100644
index 0000000..6454190
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png
new file mode 100644
index 0000000..cee9393
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png
new file mode 100644
index 0000000..cee9393
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png
new file mode 100644
index 0000000..437ffdd
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png
new file mode 100644
index 0000000..d2e14ad
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png
new file mode 100644
index 0000000..4e2f5bc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png
new file mode 100644
index 0000000..4e2f5bc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png
new file mode 100644
index 0000000..4e2f5bc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png
new file mode 100644
index 0000000..4e2f5bc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png
new file mode 100644
index 0000000..4e2f5bc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png
new file mode 100644
index 0000000..f1bcfa3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png
new file mode 100644
index 0000000..ede2fec
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png
new file mode 100644
index 0000000..94ce017
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png
new file mode 100644
index 0000000..647cfe3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png
new file mode 100644
index 0000000..b3bf923
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png
new file mode 100644
index 0000000..ae95b2b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png
new file mode 100644
index 0000000..b8e4bd6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png
new file mode 100644
index 0000000..ec6d6d7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png
new file mode 100644
index 0000000..c0e493f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png
new file mode 100644
index 0000000..2494fd4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png
new file mode 100644
index 0000000..2494fd4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png
new file mode 100644
index 0000000..2494fd4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png
new file mode 100644
index 0000000..2494fd4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png
new file mode 100644
index 0000000..2494fd4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png
new file mode 100644
index 0000000..2494fd4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png
new file mode 100644
index 0000000..dff391f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png
new file mode 100644
index 0000000..b135338
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png
new file mode 100644
index 0000000..ea09a31
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png
new file mode 100644
index 0000000..f9a4391
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png
new file mode 100644
index 0000000..d9606e1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png
new file mode 100644
index 0000000..df2d9d0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png
new file mode 100644
index 0000000..625a322
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png
new file mode 100644
index 0000000..79e8dde
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png
new file mode 100644
index 0000000..e99c266
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png
new file mode 100644
index 0000000..f0329a4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png
new file mode 100644
index 0000000..42c40b7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png
new file mode 100644
index 0000000..807491f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png
new file mode 100644
index 0000000..dfec9cc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png
new file mode 100644
index 0000000..0ed59ea
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
deleted file mode 100644
index a7a972c..0000000
--- a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
deleted file mode 100644
index dd8910b..0000000
--- a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png
index 4970f56..d6a0ab2 100644
--- a/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png
index 38b8e8b..a01ac10 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png
index d6002a7..d3602d9 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
deleted file mode 100644
index 1881f54..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
deleted file mode 100644
index 6f8ec2d..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
deleted file mode 100644
index c954ed9..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
deleted file mode 100644
index 9d1a47e..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
deleted file mode 100644
index ce63631..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
deleted file mode 100644
index 430c134..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
deleted file mode 100644
index cdebf83..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
deleted file mode 100644
index 40ceadb..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
deleted file mode 100644
index fb13eb2..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
deleted file mode 100644
index d716fba..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
deleted file mode 100644
index b8be041..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
deleted file mode 100644
index bad0c3c..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
deleted file mode 100644
index a6368fb..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
deleted file mode 100644
index 234e5d1..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
deleted file mode 100644
index 3e7796d..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
deleted file mode 100644
index 0673999..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_off_qntm_alpha.png
deleted file mode 100644
index 2a17861..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_on_qntm_alpha.png
deleted file mode 100644
index 61067ac..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_on_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png
new file mode 100644
index 0000000..b754381
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png
new file mode 100644
index 0000000..517d7a7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png
new file mode 100644
index 0000000..2c1d5b6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png
new file mode 100644
index 0000000..0c6ff7e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png
new file mode 100644
index 0000000..0796601
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png
new file mode 100644
index 0000000..9b4e0f8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png
new file mode 100644
index 0000000..25767eb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png
new file mode 100644
index 0000000..cd0951f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png
new file mode 100644
index 0000000..9ae8165
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png
new file mode 100644
index 0000000..efd9bc6
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png
new file mode 100644
index 0000000..fccbc9d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png
new file mode 100644
index 0000000..dddafca
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png
new file mode 100644
index 0000000..7e37433
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png
new file mode 100644
index 0000000..9bc22de
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png
new file mode 100644
index 0000000..507ed10
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png
new file mode 100644
index 0000000..6a21c7f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png
new file mode 100644
index 0000000..0d544d9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png
new file mode 100644
index 0000000..39da0ac
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png
new file mode 100644
index 0000000..d5ada12
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png
new file mode 100644
index 0000000..d4e096c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png
new file mode 100644
index 0000000..468a9b4
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png
new file mode 100644
index 0000000..ea3cd2e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png
new file mode 100644
index 0000000..0652cb0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png
new file mode 100644
index 0000000..768d2b0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png
new file mode 100644
index 0000000..1d06a90
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png
new file mode 100644
index 0000000..8a70a80
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png
new file mode 100644
index 0000000..bf9ec7f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png
new file mode 100644
index 0000000..cff07b9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png
new file mode 100644
index 0000000..40f997e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png
new file mode 100644
index 0000000..6ba84ec
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png
new file mode 100644
index 0000000..766610e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png
new file mode 100644
index 0000000..810a029
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_qntm_alpha.png
deleted file mode 100644
index fdbbbce..0000000
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_off_qntm_alpha.png
deleted file mode 100644
index 0ec2ee6..0000000
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_qntm_alpha.png
deleted file mode 100644
index b46ee1c..0000000
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_on_qntm_alpha.png
deleted file mode 100644
index 8737156..0000000
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png
new file mode 100644
index 0000000..cbc3833
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png
new file mode 100644
index 0000000..4243895
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png
new file mode 100644
index 0000000..b522d37
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png
new file mode 100644
index 0000000..647b965
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png
new file mode 100644
index 0000000..a317497
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png
new file mode 100644
index 0000000..0e4b25f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png
new file mode 100644
index 0000000..6e279d9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png
new file mode 100644
index 0000000..f0840cc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png
new file mode 100644
index 0000000..140e9e8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png
new file mode 100644
index 0000000..5cf8ec5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png
new file mode 100644
index 0000000..f9624d8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png
new file mode 100644
index 0000000..899df8c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png
new file mode 100644
index 0000000..6543e1c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png
new file mode 100644
index 0000000..cd758dd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png
new file mode 100644
index 0000000..72d950c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png
new file mode 100644
index 0000000..07bdbc9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png
new file mode 100644
index 0000000..c9af24b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png
new file mode 100644
index 0000000..01de3f5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png
new file mode 100644
index 0000000..f428bc5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png
new file mode 100644
index 0000000..ab5c008
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png
new file mode 100644
index 0000000..5b157cf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png
new file mode 100644
index 0000000..1210be2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png
new file mode 100644
index 0000000..e6b4140
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png
new file mode 100644
index 0000000..b678e08
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png
new file mode 100644
index 0000000..6ca2a69
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png
new file mode 100644
index 0000000..7de608e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png
new file mode 100644
index 0000000..b2bbcce
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png
new file mode 100644
index 0000000..6950db3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png
new file mode 100644
index 0000000..c790756
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png
new file mode 100644
index 0000000..ed5d888
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png
new file mode 100644
index 0000000..81a4a63
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png
new file mode 100644
index 0000000..db1d93a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png
new file mode 100644
index 0000000..198ac07
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png
new file mode 100644
index 0000000..eff3dd0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png
new file mode 100644
index 0000000..000a23a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png
new file mode 100644
index 0000000..394d661
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png
new file mode 100644
index 0000000..4e7311d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png
new file mode 100644
index 0000000..d9dcf91
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png
new file mode 100644
index 0000000..674142e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png
new file mode 100644
index 0000000..674142e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png
new file mode 100644
index 0000000..9d4026a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png
new file mode 100644
index 0000000..bb4b426
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png
new file mode 100644
index 0000000..a37076d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png
new file mode 100644
index 0000000..a37076d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png
new file mode 100644
index 0000000..a37076d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png
new file mode 100644
index 0000000..a37076d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png
new file mode 100644
index 0000000..a37076d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png
new file mode 100644
index 0000000..22e9951
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png
new file mode 100644
index 0000000..14e6b39
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png
new file mode 100644
index 0000000..86b2c01
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png
new file mode 100644
index 0000000..1c565df
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png
new file mode 100644
index 0000000..b825449
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png
new file mode 100644
index 0000000..170c234
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png
new file mode 100644
index 0000000..5477007
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png
new file mode 100644
index 0000000..eff3dd0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png
new file mode 100644
index 0000000..e3fd96a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png
new file mode 100644
index 0000000..198ac07
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png
new file mode 100644
index 0000000..198ac07
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png
new file mode 100644
index 0000000..198ac07
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png
new file mode 100644
index 0000000..198ac07
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png
new file mode 100644
index 0000000..198ac07
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png
new file mode 100644
index 0000000..198ac07
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png
new file mode 100644
index 0000000..0d6a39a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png
new file mode 100644
index 0000000..f235aed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png
new file mode 100644
index 0000000..46aa533
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png
new file mode 100644
index 0000000..a749469
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png
new file mode 100644
index 0000000..ef43f00
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png
new file mode 100644
index 0000000..eebddc3
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png
new file mode 100644
index 0000000..44b654d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png
new file mode 100644
index 0000000..6e768c1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png
new file mode 100644
index 0000000..2ac6dae
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png
new file mode 100644
index 0000000..91c49ce
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png
new file mode 100644
index 0000000..4b4bd1f
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png
new file mode 100644
index 0000000..637e596
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png
new file mode 100644
index 0000000..42d4d2a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png
new file mode 100644
index 0000000..995d1b2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
deleted file mode 100644
index 8d79a13..0000000
--- a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
deleted file mode 100644
index e0e4ef9..0000000
--- a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png
index 74a259b..a8067cb 100644
--- a/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png
index 93469a2..75085ce 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png
index b3493e7..e2eb5be 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png
new file mode 100644
index 0000000..f0ff1a7
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png
new file mode 100644
index 0000000..b382df3
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png
new file mode 100644
index 0000000..8cb4ce2
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png
new file mode 100644
index 0000000..4db2b01
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png
new file mode 100644
index 0000000..8c4709b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png
new file mode 100644
index 0000000..1ad960a
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png
new file mode 100644
index 0000000..e47cc20
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png
new file mode 100644
index 0000000..c4d0d51
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png
new file mode 100644
index 0000000..915d56a
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png
new file mode 100644
index 0000000..85795cb
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png
new file mode 100644
index 0000000..157fd91
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png
new file mode 100644
index 0000000..9d446de
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png
new file mode 100644
index 0000000..dfac1f0
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png
new file mode 100644
index 0000000..aed6c08
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png
new file mode 100644
index 0000000..1b8bd6b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png
new file mode 100644
index 0000000..5dd0e5b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png
new file mode 100644
index 0000000..5dd0e5b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png
new file mode 100644
index 0000000..1a31ad9
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png
new file mode 100644
index 0000000..63c7f12
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png
new file mode 100644
index 0000000..847dd08
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png
new file mode 100644
index 0000000..b93f3cc
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png
new file mode 100644
index 0000000..1e3dea7
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png
new file mode 100644
index 0000000..5a85238
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png
new file mode 100644
index 0000000..35960ca
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png
new file mode 100644
index 0000000..6db5555
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png
new file mode 100644
index 0000000..a9c5851
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png
new file mode 100644
index 0000000..38465bd
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png
new file mode 100644
index 0000000..15942dc
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png
new file mode 100644
index 0000000..67d0d64
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png
new file mode 100644
index 0000000..69b5c1b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png
new file mode 100644
index 0000000..0e5d331
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png
new file mode 100644
index 0000000..f0ff1a7
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png
new file mode 100644
index 0000000..01eeefe
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png
new file mode 100644
index 0000000..44028af
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png
new file mode 100644
index 0000000..ec13a86
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png
new file mode 100644
index 0000000..43754eb
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png
new file mode 100644
index 0000000..39d1d64
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png
new file mode 100644
index 0000000..f36f883
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png
new file mode 100644
index 0000000..7a4cc5c
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png
new file mode 100644
index 0000000..80a21ec
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png
new file mode 100644
index 0000000..2141104
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png
new file mode 100644
index 0000000..203bd51
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png
new file mode 100644
index 0000000..5df6fc5
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png
new file mode 100644
index 0000000..6d0fced
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png
new file mode 100644
index 0000000..8c0c372
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png
new file mode 100644
index 0000000..4fa6f53
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png
new file mode 100644
index 0000000..d3dbf7d
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png
new file mode 100644
index 0000000..4ccf8de
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png
new file mode 100644
index 0000000..adef871
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png
new file mode 100644
index 0000000..adef871
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png
new file mode 100644
index 0000000..9fc3556
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png
new file mode 100644
index 0000000..7f00609
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png
new file mode 100644
index 0000000..e4aa58d
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png
new file mode 100644
index 0000000..fe4e4b7
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png
new file mode 100644
index 0000000..86666ca
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png
new file mode 100644
index 0000000..608faaf
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png
new file mode 100644
index 0000000..ec95422
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png
new file mode 100644
index 0000000..76e2754
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png
new file mode 100644
index 0000000..3853eac
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png
new file mode 100644
index 0000000..621aff1
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png
new file mode 100644
index 0000000..d24be2a
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png
new file mode 100644
index 0000000..df33892
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png
new file mode 100644
index 0000000..ff4b818
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png
new file mode 100644
index 0000000..d9793ae
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png
new file mode 100644
index 0000000..44028af
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png
new file mode 100644
index 0000000..8b202c6
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png
new file mode 100644
index 0000000..3b497f3
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png
new file mode 100644
index 0000000..532b6de
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png
new file mode 100644
index 0000000..403b2fe
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png
new file mode 100644
index 0000000..8c5086c
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png
new file mode 100644
index 0000000..d4870f8
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png
new file mode 100644
index 0000000..c05adf5
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png
new file mode 100644
index 0000000..99b2056
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png
new file mode 100644
index 0000000..d839358
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png
new file mode 100644
index 0000000..913f94d
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png
new file mode 100644
index 0000000..7f325b3
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png
new file mode 100644
index 0000000..149a9aa
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png
new file mode 100644
index 0000000..95c219e
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png
new file mode 100644
index 0000000..462a128
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png
new file mode 100644
index 0000000..5911d16
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png
new file mode 100644
index 0000000..e0c6d85
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png
new file mode 100644
index 0000000..5679943
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png
new file mode 100644
index 0000000..54b636d
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png
new file mode 100644
index 0000000..bf9fac0
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png
new file mode 100644
index 0000000..25d5319
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png
new file mode 100644
index 0000000..d2df595
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png
new file mode 100644
index 0000000..7700bde
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png
new file mode 100644
index 0000000..883f98b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png
new file mode 100644
index 0000000..b3b2108
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png
new file mode 100644
index 0000000..3aad596
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png
new file mode 100644
index 0000000..2017e17
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png
new file mode 100644
index 0000000..1fc2700
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png
new file mode 100644
index 0000000..bb8b0f2
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png
new file mode 100644
index 0000000..66ab8f6
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png
new file mode 100644
index 0000000..e3424db
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png
new file mode 100755
index 0000000..c06740b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png
new file mode 100755
index 0000000..7556167
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png
new file mode 100644
index 0000000..0c8f746
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png
new file mode 100644
index 0000000..5db9deb
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png
new file mode 100644
index 0000000..3aca6d3
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png
new file mode 100644
index 0000000..746c74f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png
new file mode 100644
index 0000000..454a5b2
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png
new file mode 100644
index 0000000..80ad8cc
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png
new file mode 100644
index 0000000..cfd0db4
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png
new file mode 100644
index 0000000..845092f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png
new file mode 100644
index 0000000..0042db4
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png
new file mode 100644
index 0000000..77b2901
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png
new file mode 100644
index 0000000..fb3c238
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png
new file mode 100644
index 0000000..0d28c45
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png
new file mode 100644
index 0000000..fb07f2a
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_borderless_quantum.xml b/core/res/res/drawable/btn_borderless_quantum.xml
index a8def44..2cd7ed6 100644
--- a/core/res/res/drawable/btn_borderless_quantum.xml
+++ b/core/res/res/drawable/btn_borderless_quantum.xml
@@ -16,21 +16,6 @@
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
     android:tint="?attr/colorControlHighlight">
-    <item android:id="@id/mask">
-        <inset
-            android:insetLeft="4dp"
-            android:insetTop="4dp"
-            android:insetBottom="4dp"
-            android:insetRight="4dp">
-            <shape android:shape="rectangle">
-                <solid android:color="@color/white" />
-                <corners android:radius="2dp" />
-                <padding
-                    android:left="4dp"
-                    android:top="4dp"
-                    android:bottom="4dp"
-                    android:right="4dp" />
-            </shape>
-        </inset>
-    </item>
+    <item android:id="@id/mask"
+        android:drawable="@drawable/btn_qntm_alpha" />
 </ripple>
diff --git a/core/res/res/drawable/btn_check_quantum.xml b/core/res/res/drawable/btn_check_quantum.xml
deleted file mode 100644
index 6ceba60..0000000
--- a/core/res/res/drawable/btn_check_quantum.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true" android:state_pressed="true">
-        <bitmap android:src="@drawable/btn_check_on_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:state_checked="true">
-        <bitmap android:src="@drawable/btn_check_on_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:state_pressed="true">
-        <bitmap android:src="@drawable/btn_check_off_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item>
-        <bitmap android:src="@drawable/btn_check_off_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-</selector>
diff --git a/core/res/res/drawable/btn_check_quantum_anim.xml b/core/res/res/drawable/btn_check_quantum_anim.xml
index 96715a4..b16875e 100644
--- a/core/res/res/drawable/btn_check_quantum_anim.xml
+++ b/core/res/res/drawable/btn_check_quantum_anim.xml
@@ -16,88 +16,118 @@
 
 <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_check_anim_00015_qntm_alpha"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_check_to_on_qntm_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_enabled="false">
-        <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_check_to_on_qntm_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_checked="true" android:id="@+id/on">
-        <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
+        <bitmap android:src="@drawable/btn_check_to_on_qntm_015" android:tint="?attr/colorControlActivated" />
     </item>
     <item android:id="@+id/off">
-        <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
+        <bitmap android:src="@drawable/btn_check_to_on_qntm_000" android:tint="?attr/colorControlNormal" />
     </item>
-    <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+    <transition android:fromId="@+id/off" android:toId="@+id/on">
         <animation-list>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_000" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00001_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_001" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00002_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_002" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00003_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_003" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00004_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_004" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00005_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_005" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00006_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_006" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00007_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_007" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00008_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_008" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00009_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_009" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00010_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_010" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00011_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_011" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00012_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_012" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00013_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_013" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00014_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_014" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_on_qntm_015" android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+    <transition android:fromId="@+id/on" android:toId="@+id/off">
+        <animation-list>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_000" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_001" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_002" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_003" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_004" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_005" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_006" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_007" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_008" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_009" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_010" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_011" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_012" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_013" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_014" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_check_to_off_qntm_015" android:tint="?attr/colorControlActivated" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/btn_default_quantum.xml b/core/res/res/drawable/btn_default_quantum.xml
index 63473a4..61193fe 100644
--- a/core/res/res/drawable/btn_default_quantum.xml
+++ b/core/res/res/drawable/btn_default_quantum.xml
@@ -17,20 +17,7 @@
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
     android:tint="?attr/colorControlHighlight">
     <item>
-        <inset
-            android:insetLeft="4dp"
-            android:insetTop="4dp"
-            android:insetBottom="4dp"
-            android:insetRight="4dp">
-            <shape android:shape="rectangle">
-                <solid android:color="?attr/colorButtonNormal" />
-                <corners android:radius="2dp" />
-                <padding
-                    android:left="4dp"
-                    android:top="4dp"
-                    android:bottom="4dp"
-                    android:right="4dp" />
-            </shape>
-        </inset>
+        <nine-patch android:src="@drawable/btn_qntm_alpha"
+            android:tint="?attr/colorButtonNormal" />
     </item>
 </ripple>
diff --git a/core/res/res/drawable/btn_radio_quantum.xml b/core/res/res/drawable/btn_radio_quantum.xml
deleted file mode 100644
index 0f9ebce..0000000
--- a/core/res/res/drawable/btn_radio_quantum.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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.
--->
-
-<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_on_qntm_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
-    </item>
-    <item android:state_enabled="false">
-        <bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
-    </item>
-    <item android:state_checked="true">
-        <bitmap android:src="@drawable/btn_radio_on_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item>
-        <bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-</selector>
diff --git a/core/res/res/drawable/btn_radio_quantum_anim.xml b/core/res/res/drawable/btn_radio_quantum_anim.xml
index 5068b7a..cd9b518 100644
--- a/core/res/res/drawable/btn_radio_quantum_anim.xml
+++ b/core/res/res/drawable/btn_radio_quantum_anim.xml
@@ -16,88 +16,118 @@
 
 <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_anim_00015_qntm_alpha"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_enabled="false">
-        <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_radio_to_on_qntm_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_anim_00015_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
+        <bitmap android:src="@drawable/btn_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" />
     </item>
     <item android:id="@+id/off">
-        <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
+        <bitmap android:src="@drawable/btn_radio_to_on_qntm_000" android:tint="?attr/colorControlNormal" />
     </item>
-    <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+    <transition android:fromId="@+id/off" android:toId="@+id/on">
         <animation-list>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_000" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00001_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_001" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00002_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_002" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00003_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_003" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00004_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_004" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00005_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_005" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00006_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_006" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00007_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_007" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00008_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_008" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00009_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_009" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00010_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_010" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00011_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_011" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00012_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_012" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00013_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_013" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00014_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_014" android:tint="?attr/colorControlActivated" />
             </item>
-            <item android:duration="33">
-                <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+    <transition android:fromId="@+id/on" android:toId="@+id/off">
+        <animation-list>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_000" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_001" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_002" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_003" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_004" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_005" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_006" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_007" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_008" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_009" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_010" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_011" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_012" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_013" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_014" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_radio_to_off_qntm_015" android:tint="?attr/colorControlActivated" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/btn_toggle_quantum.xml b/core/res/res/drawable/btn_toggle_quantum.xml
new file mode 100644
index 0000000..e235598
--- /dev/null
+++ b/core/res/res/drawable/btn_toggle_quantum.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="4dp"
+    android:insetTop="4dp"
+    android:insetBottom="4dp"
+    android:insetRight="4dp">
+    <layer-list android:paddingMode="stack">
+        <item>
+            <ripple android:tint="?attr/colorControlHighlight">
+                <item>
+                    <nine-patch android:src="@drawable/btn_toggle_qntm_alpha"
+                        android:tint="?attr/colorButtonNormal" />
+                </item>
+            </ripple>
+        </item>
+        <item>
+            <selector xmlns:android="http://schemas.android.com/apk/res/android">
+                <item android:state_checked="false">
+                    <nine-patch android:src="@drawable/btn_toggle_indicator_qntm_alpha"
+                        android:tint="?attr/colorControlNormal" />
+                </item>
+                <item android:state_checked="true">
+                    <nine-patch android:src="@drawable/btn_toggle_indicator_qntm_alpha"
+                        android:tint="?attr/colorControlActivated" />
+                </item>
+            </selector>
+        </item>
+    </layer-list>
+</inset>
diff --git a/core/res/res/drawable/ic_audio_ring_notif.xml b/core/res/res/drawable/ic_audio_ring_notif.xml
index 247d1b4..b52db5c 100644
--- a/core/res/res/drawable/ic_audio_ring_notif.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif.xml
@@ -1,23 +1,28 @@
-<?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.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_ring_notif_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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 72aaa9d..8d7d6cb 100644
--- a/core/res/res/drawable/ic_audio_ring_notif_mute.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif_mute.xml
@@ -1,23 +1,28 @@
-<?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.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_ring_notif_mute_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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 9e31aba..2f1d940 100644
--- a/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
+++ b/core/res/res/drawable/ic_audio_ring_notif_vibrate.xml
@@ -1,23 +1,28 @@
-<?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.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_ring_notif_vibrate_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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/scrubber_control_quantum_anim.xml b/core/res/res/drawable/scrubber_control_quantum_anim.xml
new file mode 100644
index 0000000..87d3ae9
--- /dev/null
+++ b/core/res/res/drawable/scrubber_control_quantum_anim.xml
@@ -0,0 +1,74 @@
+<?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.
+-->
+
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true">
+    <item android:state_enabled="false" android:state_pressed="true">
+        <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_pressed="true" android:id="@+id/pressed">
+        <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/not_pressed">
+        <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+    </item>
+    <transition android:fromId="@+id/not_pressed" android:toId="@+id/pressed">
+        <animation-list>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+    <transition android:fromId="@+id/pressed" android:toId="@+id/not_pressed">
+        <animation-list>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+</animated-selector>
diff --git a/core/res/res/drawable/switch_inner_quantum.xml b/core/res/res/drawable/switch_inner_quantum.xml
deleted file mode 100644
index 856895e..0000000
--- a/core/res/res/drawable/switch_inner_quantum.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:state_checked="true">
-        <nine-patch android:src="@drawable/switch_on_qntm_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
-    </item>
-    <item android:state_enabled="false">
-        <nine-patch android:src="@drawable/switch_off_qntm_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
-    </item>
-    <item android:state_checked="true">
-        <nine-patch android:src="@drawable/switch_on_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item>
-        <nine-patch android:src="@drawable/switch_off_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-</selector>
diff --git a/core/res/res/drawable/switch_thumb_quantum_anim.xml b/core/res/res/drawable/switch_thumb_quantum_anim.xml
new file mode 100644
index 0000000..1984d47
--- /dev/null
+++ b/core/res/res/drawable/switch_thumb_quantum_anim.xml
@@ -0,0 +1,128 @@
+<?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.
+-->
+
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true">
+    <item android:state_enabled="false" android:state_checked="true">
+        <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/btn_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_checked="true" android:id="@+id/on">
+        <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/off">
+        <bitmap android:src="@drawable/btn_switch_to_on_qntm_000" android:gravity="center" 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_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_006" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_007" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_008" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_009" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_010" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_011" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_012" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_013" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+    <transition android:fromId="@+id/on" android:toId="@+id/off">
+        <animation-list>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_006" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_007" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_008" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_009" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_010" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_011" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_012" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_013" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="15">
+                <bitmap android:src="@drawable/btn_switch_to_off_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+</animated-selector>
diff --git a/core/res/res/drawable/switch_track_quantum.xml b/core/res/res/drawable/switch_track_quantum.xml
index 8c4e6b71..3651a0a 100644
--- a/core/res/res/drawable/switch_track_quantum.xml
+++ b/core/res/res/drawable/switch_track_quantum.xml
@@ -15,6 +15,16 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:state_checked="true">
+        <nine-patch android:src="@drawable/switch_track_qntm_alpha"
+            android:tint="?attr/colorControlActivated"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_enabled="false">
+        <nine-patch android:src="@drawable/switch_track_qntm_alpha"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
     <item android:state_checked="true">
         <nine-patch android:src="@drawable/switch_track_qntm_alpha"
             android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml
index 79401af..a358623 100644
--- a/core/res/res/layout/global_actions_silent_mode.xml
+++ b/core/res/res/layout/global_actions_silent_mode.xml
@@ -37,7 +37,7 @@
             android:layout_marginEnd="8dp"
             android:layout_marginTop="6dp"
             android:layout_marginBottom="6dp"
-            android:src="@drawable/ic_audio_vol_mute"
+            android:src="@drawable/ic_audio_ring_notif_mute"
             android:scaleType="center"
             android:duplicateParentState="true"
             android:background="@drawable/silent_mode_indicator"
@@ -94,7 +94,7 @@
             android:layout_marginEnd="8dp"
             android:layout_marginTop="6dp"
             android:layout_marginBottom="6dp"
-            android:src="@drawable/ic_audio_vol"
+            android:src="@drawable/ic_audio_ring_notif"
             android:scaleType="center"
             android:duplicateParentState="true"
             android:background="@drawable/silent_mode_indicator"
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
deleted file mode 100644
index 3ad1f23..0000000
--- a/core/res/res/layout/volume_adjust.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/visible_panel"
-    android:orientation="horizontal"
-    android:layout_width="300dp"
-    android:layout_height="wrap_content">
-
-    <LinearLayout
-        android:id="@+id/slider_group"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:orientation="vertical">
-        <!-- Sliders go here -->
-    </LinearLayout>
-
-    <ImageView
-        android:id="@+id/expand_button_divider"
-        android:src="?attr/dividerVertical"
-        android:layout_width="wrap_content"
-        android:layout_height="32dip"
-        android:scaleType="fitXY"
-        android:layout_gravity="top"
-        android:layout_marginTop="16dip"
-        android:layout_marginBottom="16dip" />
-
-    <ImageView
-        android:id="@+id/expand_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:padding="16dip"
-        android:background="?attr/selectableItemBackground"
-        android:src="@drawable/ic_sysbar_quicksettings" />
-
-</LinearLayout>
diff --git a/core/res/res/layout/volume_adjust_item.xml b/core/res/res/layout/volume_adjust_item.xml
deleted file mode 100644
index 57cecf4..0000000
--- a/core/res/res/layout/volume_adjust_item.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="80dip"
-    android:orientation="horizontal"
-    android:layout_marginTop="8dip"
-    android:layout_marginBottom="8dip"
-    android:gravity="start|center_vertical">
-
-    <ImageView
-        android:id="@+id/stream_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingLeft="16dip"
-        android:background="?attr/selectableItemBackground"
-        android:contentDescription="@null" />
-
-    <SeekBar
-        style="?android:attr/seekBarStyle"
-        android:id="@+id/seekbar"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:padding="16dip"
-        android:layout_marginEnd="16dip" />
-
-</LinearLayout>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index df59abe..b17b8c6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -267,7 +267,7 @@
     <string name="permdesc_statusBarService" msgid="716113660795976060">"Tillader, at appen er statusbjælken."</string>
     <string name="permlab_expandStatusBar" msgid="1148198785937489264">"udvid/skjul statuslinje"</string>
     <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Tillader, at appen kan udvide og skjule statusbjælken."</string>
-    <string name="permlab_install_shortcut" msgid="4279070216371564234">"installer genveje"</string>
+    <string name="permlab_install_shortcut" msgid="4279070216371564234">"installere genveje"</string>
     <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Tillader, at en applikation føjer genveje til startskærmen uden brugerindgriben."</string>
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"afinstaller genveje"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Tillader, at applikationen fjerner genveje på startskærmen uden brugerindgriben."</string>
@@ -281,7 +281,7 @@
     <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Tillader, at appen kan modtage og behandle nødtransmissioner. Denne tilladelse er kun tilgængelig for systemapps."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"læse Cell Broadcast-beskeder"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Tillader, at appen læser Cell Broadcast-beskeder, der modtages af din enhed. I nogle områder sendes der Cell Broadcast-beskeder for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af ​din ​enhed, når der modtages en Cell Broadcast-besked om en nødsituation."</string>
-    <string name="permlab_sendSms" msgid="5600830612147671529">"send sms-beskeder"</string>
+    <string name="permlab_sendSms" msgid="5600830612147671529">"sende sms-beskeder"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Tillader, at appen kan sende sms-beskeder. Dette kan resultere i uventede opkrævninger. Skadelige apps kan koste dig penge ved at sende beskeder uden din bekræftelse."</string>
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"send hændelser, hvor der skal svares pr. besked"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"Tillader, at appen kan sende anmodninger til andre apps til beskeder for at håndtere hændelser, hvor der skal svares pr. besked."</string>
@@ -295,7 +295,7 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Tillader, at appen kan modtage og behandle WAP-beskeder. Denne tilladelse omfatter muligheden for at overvåge eller slette de beskeder, der sendes til dig, 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>
-    <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kommuniker på tværs af brugere"</string>
+    <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>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Tillader alle mulige former for kommunikation på tværs af brugere."</string>
@@ -325,7 +325,7 @@
     <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Tillader, at appen kan tvinge andre apps til at stoppe."</string>
     <string name="permlab_forceBack" msgid="652935204072584616">"tvinge appen til at lukke"</string>
     <string name="permdesc_forceBack" msgid="3892295830419513623">"Tillader, at appen kan tvinge enhver aktivitet i forgrunden til at lukke og gå tilbage. Bør aldrig være nødvendigt til almindelige apps."</string>
-    <string name="permlab_dump" msgid="1681799862438954752">"hent intern systemtilstand"</string>
+    <string name="permlab_dump" msgid="1681799862438954752">"hente intern systemtilstand"</string>
     <string name="permdesc_dump" msgid="1778299088692290329">"Tillader, at appen kan hente systemets interne tilstand. Ondsindede apps kan hente en lang række fortrolige og beskyttede oplysninger, som de normalt aldrig ville have brug for."</string>
     <string name="permlab_retrieve_window_content" msgid="8022588608994589938">"hente skærmindhold"</string>
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Tillader, at appen kan hente indholdet i det aktive vindue. Ondsindede apps kan hente al indholdet i vinduet og undersøge al dens tekst med undtagelse af adgangskoder."</string>
@@ -359,7 +359,7 @@
     <string name="permdesc_batteryStats" msgid="5897346582882915114">"Tillader, at en applikation læser de aktuelle data for batteriforbruget. Kan tillade, at applikationen henter detaljerede oplysninger om, hvilke apps du bruger."</string>
     <string name="permlab_updateBatteryStats" msgid="3719689764536379557">"rediger batteristatistikker"</string>
     <string name="permdesc_updateBatteryStats" msgid="6862817857178025002">"Tillader, at appen kan ændre indsamlede batteristatistikker. Anvendes ikke af normale apps."</string>
-    <string name="permlab_getAppOpsStats" msgid="1508779687436585744">"hent statistikker for handlinger i appen"</string>
+    <string name="permlab_getAppOpsStats" msgid="1508779687436585744">"hente statistikker om handlinger i appen"</string>
     <string name="permdesc_getAppOpsStats" msgid="6243887041577912877">"Tillader, at appen indhenter statistikker for handlinger i applikationen. Denne handling bruges ikke i almindelige apps."</string>
     <string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"lav ændringer i statistik for handlinger i appen"</string>
     <string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"Tillader, at appen kan ændre indsamlede statistikker for handlinger i applikationen. Dette kan ikke bruges af almindelige apps."</string>
@@ -474,7 +474,7 @@
     <string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontaktpersoner"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Tillader, at appen kan ændre data om de kontaktpersoner, der er gemt på din tablet, f.eks. hvor ofte du har ringet til dem, sendt dem en e-mail eller på anden måde kommunikeret med bestemte kontaktpersoner. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Tillader, at appen kan ændre data om de kontaktpersoner, der er gemt på din telefon, f.eks. hvor ofte du har ringet til dem, sendt en e-mail til dem eller på anden måde kommunikeret med bestemte kontaktpersoner. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
-    <string name="permlab_readCallLog" msgid="3478133184624102739">"læs opkaldsliste"</string>
+    <string name="permlab_readCallLog" msgid="3478133184624102739">"læse opkaldsliste"</string>
     <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Tillader, at appen kan læse din tablets opkaldsliste, f.eks. data om indgående og udgående opkald. Med denne tilladelse kan apps gemme dine opkaldslistedata, og skadelige apps kan dele opkaldslistedata uden din viden."</string>
     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Tillader, at appen kan læse telefonens opkaldsliste, f.eks. data om indgående og udgående opkald. Med denne tilladelse kan apps gemme dine opkaldslistedata, og skadelige apps kan dele disse opkaldslistedata uden din viden."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"skriv opkaldsliste"</string>
@@ -486,9 +486,9 @@
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Tillader, at appen kan ændre eller tilføje oplysninger i din personlige profil, der er gemt på din enhed, f.eks. dit navn eller dine kontaktoplysninger. Dette betyder, at andre apps kan identificere dig og sende profiloplysninger til andre."</string>
     <string name="permlab_bodySensors" msgid="4871091374767171066">"kropssensorer (f.eks. pulsmålere)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Tillader, at appen får adgang til data fra sensorer, du bruger til at måle, hvad der sker inde i din krop, f.eks. din puls."</string>
-    <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"læs din sociale strøm"</string>
+    <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"læse din sociale strøm"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Tillader, at appen kan få adgang til og synkronisere sociale opdateringer fra dig og dine venner. Vær forsigtig, når du deler oplysninger – med denne tilladelse kan appen læse kommunikation mellem dig og dine venner på sociale netværk, uanset fortrolighed. Bemærk! Denne tilladelse håndhæves muligvis ikke på alle sociale netværk."</string>
-    <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skriv i din sociale strøm"</string>
+    <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skrive i din sociale strøm"</string>
     <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Tillader, at appen kan vise sociale opdateringer fra dine venner. Vær forsigtig, når du deler oplysninger – med denne tilladelse kan appen producere meddelelser, der kan synes at komme fra en ven. Bemærk! Denne tilladelse håndhæves muligvis ikke på alle sociale netværk."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"læse kalenderbegivenheder og fortrolige oplysninger"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Tillader, at appen kan læse alle de kalenderbegivenheder, der er gemt på din tablet, f.eks. venners eller kollegers. Med denne tilladelse kan appen dele eller gemme dine kalenderdata, uanset fortrolighed eller følsomhed."</string>
@@ -526,7 +526,7 @@
     <string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"Tillader, at appen opfanger og omdirigerer et sikkert videooutput."</string>
     <string name="permlab_mediaContentControl" msgid="8749790560720562511">"kontrollér medieafspilning og metadataadgang"</string>
     <string name="permdesc_mediaContentControl" msgid="1637478200272062">"Tillader, at appen styrer medieafspilning og får adgang til medieoplysninger (titel, forfatter...)."</string>
-    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"skift dine lydindstillinger"</string>
+    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"skifte dine lydindstillinger"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Tillader, at appen kan ændre globale lydindstillinger, som f.eks. lydstyrke og hvilken højttaler der bruges til output."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"optage lyd"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Tillader, at appen kan optage lyd med mikrofonen. Med denne tilladelse kan appen til enhver tid optage lyd uden din bekræftelse."</string>
@@ -632,7 +632,7 @@
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Tillader, at appen kan oprette netværkssockets og bruge tilpassede netværksprotokoller. Browseren og andre applikationer indeholder midler til at sende data til internettet, så med denne tilladelse er der ingen forpligtelse til at sende data til internettet."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"ændre/opfange netværksindstillinger og trafik"</string>
     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Tillader, at appen kan ændre netværksindstillinger og opsnappe og inspicere al netværkstrafik, f.eks. for at ændre proxy og port for et adgangspunkt. Ondsindede apps kan overvåge, omdirigere eller ændre netværkspakker uden din viden."</string>
-    <string name="permlab_changeNetworkState" msgid="958884291454327309">"skift netværksforbindelse"</string>
+    <string name="permlab_changeNetworkState" msgid="958884291454327309">"skifte netværksforbindelse"</string>
     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Tillader, at appen kan ændre netværksforbindelsens tilstand."</string>
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"skifte forbindelse til netdeling"</string>
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Tillader, at appen kan ændre tilstand for en netværksforbindelse via netdeling."</string>
@@ -672,9 +672,9 @@
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Tillader, at en app kan ændre synkroniseringsindstillingerne for en konto. Denne tilladelse kan f.eks. anvendes til at aktivere synkronisering af appen Personer med en konto."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"læse synkroniseringsstatistikker"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Tillader, at en app kan læse synkroniseringsstatistikkerne for en konto, f.eks. historikken for synkroniserede begivenheder og hvor meget data der synkroniseres."</string>
-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"læs abonnerede feeds"</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"læse feeds, jeg abonnerer på"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Tillader, at appen kan hente oplysninger om de feeds, der synkroniseres."</string>
-    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"skriv abonnerede feeds"</string>
+    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"skrive feeds, som jeg abonnerer på"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Tillader, at appen kan ændre dine synkroniserede feeds. Ondsindede apps kan ændre dine synkroniserede feeds."</string>
     <string name="permlab_readDictionary" msgid="4107101525746035718">"læse termer, som du har føjet til ordbogen"</string>
     <string name="permdesc_readDictionary" msgid="659614600338904243">"Tillader, at appen kan læse alle ord, navne og sætninger, som brugeren har gemt i brugerordbogen."</string>
@@ -995,7 +995,7 @@
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Tillader, at appen kan ændre browserens historik eller de bogmærker, der er gemt på din telefon. Dette kan give appen tilladelse til at slette eller ændre browserdata. Bemærk! Denne tilladelse håndhæves muligvis ikke af tredjepartsbrowsere eller andre applikationer med websøgningsfunktioner."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"indstille en alarm"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Tillader, at appen kan indstille en alarm i en installeret alarmapp. Nogle alarmapps har muligvis ikke denne funktion."</string>
-    <string name="permlab_addVoicemail" msgid="5525660026090959044">"tilføj telefonsvarer"</string>
+    <string name="permlab_addVoicemail" msgid="5525660026090959044">"tilføje telefonsvarer"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Tillader, at appen kan tilføje beskeder på din telefonsvarer."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geografisk placering i Browser"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websites."</string>
@@ -1275,7 +1275,7 @@
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"Angiv dato"</string>
     <string name="date_time_set" msgid="5777075614321087758">"Angiv"</string>
     <string name="date_time_done" msgid="2507683751759308828">"Udført"</string>
-    <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NYHED! "</font></string>
+    <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NY: "</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"Leveret af <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste dig penge"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 989eec6..d0561b9 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1471,8 +1471,8 @@
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Επιλέξτε κάποια εφαρμογή"</string>
     <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Δεν ήταν δυνατή η εκκίνηση του <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινοποίηση με"</string>
-    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινοποίηση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+    <string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινή χρήση με"</string>
+    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινή χρήση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Στοιχείο χειρισμού με δυνατότητα ολίσθησης. Αγγίξτε και πατήστε παρατεταμένα."</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Σύρετε για ξεκλείδωμα."</string>
     <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Συνδέστε ακουστικά για να ακούσετε τα πλήκτρα του κωδικού πρόσβασης να εκφωνούνται."</string>
@@ -1516,7 +1516,7 @@
     <string name="sha1_fingerprint" msgid="7930330235269404581">"Αποτύπωμα SHA-1"</string>
     <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="share_action_provider_share_with" msgid="5247684435979149216">"Κοινή χρήση με"</string>
     <string name="list_delimeter" msgid="3975117572185494152">", "</string>
     <string name="sending" msgid="3245653681008218030">"Γίνεται αποστολή…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c8eca25..3d043c4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -294,7 +294,7 @@
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"recevoir des messages texte (WAP)"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Permet à l\'application de recevoir et de traiter les messages WAP. Cette autorisation lui donne la possibilité de surveiller 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 de d\'obtenir des informations sur les applications utilisées sur l\'appareil."</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>
     <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>
@@ -503,7 +503,7 @@
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"autoriser l\'installation d\'un fournisseur de services de localisation"</string>
     <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Permet de créer des sources de localisation fictives à des fins de tests ou pour installer un nouveau fournisseur de position. L\'application peut ainsi modifier la position et/ou l\'état renvoyé par d\'autres sources de localisation telles que le GPS ou les fournisseurs de position."</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"position précise (GPS et réseau)"</string>
-    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permet à l\'application d\'obtenir votre position exacte à l\'aide du récepteur satellite GPS ou des sources de localisation de réseau tels que les points d\'accès Wi-Fi et les antennes-relais. Ces services de localisation doivent être activés et disponibles sur votre appareil pour que l\'application puissent déterminer où vous vous trouvez, le cas échéant. Cette autorisation peut entraîner une utilisation accrue de la batterie."</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permet à l\'application d\'obtenir votre position exacte à l\'aide du récepteur satellite GPS ou des sources de localisation de réseau tels que les points d\'accès Wi-Fi et les antennes-relais. Ces services de localisation doivent être activés et disponibles sur votre appareil pour que l\'application puisse déterminer où vous vous trouvez, le cas échéant. Cette autorisation peut entraîner une utilisation accrue de la batterie."</string>
     <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"position approximative (réseau)"</string>
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permet à l\'application d\'obtenir votre position approximative. Celle-ci est fournie par des services de localisation sur la base des sources de localisation de réseau tels que les points d\'accès Wi-Fi et les antennes-relais. Ces services de localisation doivent être activés et disponibles sur votre appareil pour que l\'application puisse déterminer où vous vous trouvez de façon approximative, le cas échéant."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Accès à SurfaceFlinger"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 000fb3a..2adaaf1 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -496,7 +496,7 @@
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"dodajte ili izmijenite kalendarske događaje i pošaljite e-poštu gostima bez znanja vlasnika"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Aplikaciji omogućuje dodavanje, uklanjanje i promjenu događaja koje možete izmijeniti na tabletnom računalu, uključujući one od vaših prijatelja ili suradnika. To aplikaciji može omogućiti slanje poruka koje izgledaju kao da dolaze od vlasnika kalendara ili izmjenu događaja bez znanja vlasnika."</string>
     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Aplikaciji omogućuje dodavanje, uklanjanje i promjenu događaja koje možete izmijeniti na telefonu, uključujući one od vaših prijatelja ili suradnika. To aplikaciji može omogućiti slanje poruka koje izgledaju kao da dolaze od vlasnika kalendara ili izmjenu događaja bez znanja vlasnika."</string>
-    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"omogući testiranje izvora lokacije"</string>
+    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"omogućeno testiranje izvora lokacije"</string>
     <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Stvaranje lažnih izvora lokacije radi testiranja ili za instaliranje novog pružatelja usluga lokacije. To aplikaciji omogućuje zaobilaženje lokacije i/ili statusa koji vraćaju drugi izvori lokacije, primjerice GPS ili pružatelji usluga lokacije."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"pristup dodatnim naredbama davatelja lokacije"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Aplikaciji omogućuje pristup dodatnim naredbama za pružatelja usluga lokacije. To aplikaciji može omogućiti ometanje rada GPS-a ili drugih izvora lokacije."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index dbe2d7f..f3b8495 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -68,7 +68,7 @@
   </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
-    <string name="ClipMmi" msgid="6952821216480289285">"លេខ​សម្គាល់​អ្នក​ហៅ​​ចូល​"</string>
+    <string name="ClipMmi" msgid="6952821216480289285">"លេខ​សម្គាល់​អ្នក​ហៅ​​ចូល"</string>
     <string name="ClirMmi" msgid="7784673673446833091">"លេខ​សម្គាល់​អ្នក​ហៅ​ចេញ"</string>
     <string name="CfMmi" msgid="5123218989141573515">"បញ្ជូន​ការ​ហៅ​បន្ត"</string>
     <string name="CwMmi" msgid="9129678056795016867">"រង់ចាំ​ការ​ហៅ"</string>
@@ -125,7 +125,7 @@
     <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> ៖ មិន​បាន​បញ្ជូន​បន្ត"</string>
     <string name="fcComplete" msgid="3118848230966886575">"កូដ​លក្ខណៈ​ពេញលេញ។"</string>
     <string name="fcError" msgid="3327560126588500777">"បញ្ហា​ការ​តភ្ជាប់​ ឬ​កូដ​លក្ខណៈ​​​មិន​ត្រឹមត្រូវ​។"</string>
-    <string name="httpErrorOk" msgid="1191919378083472204">"យល់​ព្រម​"</string>
+    <string name="httpErrorOk" msgid="1191919378083472204">"យល់​ព្រម"</string>
     <string name="httpError" msgid="7956392511146698522">"មាន​កំហុស​បណ្ដាញ។"</string>
     <string name="httpErrorLookup" msgid="4711687456111963163">"រក​មិន​ឃើញ URL ។"</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"គ្រោងការណ៍​ផ្ទៀងផ្ទាត់​តំបន់បណ្ដាញ​មិន​ត្រូវ​បាន​គាំទ្រ។"</string>
@@ -183,7 +183,7 @@
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"បើក​សំឡេង"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ពេល​ជិះ​យន្តហោះ"</string>
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"បាន​បើក​របៀប​ពេល​ជិះ​យន្ត​ហោះ"</string>
-    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បាន​បិទ​របៀបពេលជិះ​យន្តហោះ​"</string>
+    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បាន​បិទ​របៀបពេលជិះ​យន្តហោះ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ការ​កំណត់"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
@@ -195,7 +195,7 @@
     <string name="permgrouplab_messages" msgid="7521249148445456662">"សារ​របស់​អ្នក"</string>
     <string name="permgroupdesc_messages" msgid="7821999071003699236">"អាន និង​សរសេរ​សារ SMS, អ៊ីមែល និង​សារ​ផ្សេងៗ​ទៀត​របស់​អ្នក។"</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"ព័ត៌មាន​ផ្ទាល់ខ្លួន​របស់​អ្នក"</string>
-    <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"ចូល​ដំណើរការ​ព័ត៌មាន​ដោយ​ផ្ទាល់​អំពី​អ្នក​ ដែល​បា​ន​រក្សាទុក​ក្នុង​កាត​ទំនាក់ទំនង​របស់​អ្នក។​"</string>
+    <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"ចូល​ដំណើរការ​ព័ត៌មាន​ដោយ​ផ្ទាល់​អំពី​អ្នក​ ដែល​បា​ន​រក្សាទុក​ក្នុង​កាត​ទំនាក់ទំនង​របស់​អ្នក។"</string>
     <string name="permgrouplab_socialInfo" msgid="5799096623412043791">"ព័ត៌មាន​សង្គម​របស់​អ្នក"</string>
     <string name="permgroupdesc_socialInfo" msgid="7129842457611643493">"ចូល​ដំណើរការ​ព័ត៌មាន​ដោយ​ផ្ទាល់​អំពី​ទំនាក់ទំនង និង​ការ​ភ្ជាប់​សង្គម​របស់​អ្នក។"</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"ទីតាំង​របស់​អ្នក"</string>
@@ -384,7 +384,7 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"ឲ្យ​កម្មវិធី​មើល​គ្រាប់​ចុច​ដែល​អ្នក​ចុច​ពេល​មាន​អន្តរកម្ម​ជា​មួយ​កម្មវិធី​ផ្សេង (ដូចជា បញ្ចូល​ពាក្យ​សម្ងាត់)។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"ចង​ទៅ​វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​វិធី​សាស្ត្រ​បញ្ចូល។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ចង​សេវា​កម្ម​ភាព​មធ្យោបាយ​ងាយស្រួល​"</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ចង​សេវា​កម្ម​ភាព​មធ្យោបាយ​ងាយស្រួល"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ឲ្យ​​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ភាព​ងាយស្រួល។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindPrintService" msgid="8462815179572748761">"ចង​សេវាកម្ម​​បោះពុម្ព"</string>
     <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ធាតុ​ក្រាហ្វិក។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
@@ -402,7 +402,7 @@
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​​របស់​សេវាកម្ម​អន្តរកម្ម​សំឡេង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់​ទៅ​ការ​បង្ហាញ​ពី​ចម្ងាយ"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​ការ​បង្ហាញ​ពី​ចម្ងាយ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចង​សេវា​កម្ម​ធាតុ​ក្រាហ្វិក​"</string>
+    <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចង​សេវា​កម្ម​ធាតុ​ក្រាហ្វិក"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ធាតុ​ក្រាហ្វិក។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ភ្ជាប់​ទៅ​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​ច្រក"</string>
     <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ក្រុមហ៊ុន​ផ្ដល់​​ច្រក​ដែល​បាន​ចុះ​ឈ្មោះ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
@@ -410,7 +410,7 @@
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យ​ម្ចាស់​ផ្ញើ​គោលបំណង​​ទៅ​អ្នក​គ្រប់គ្រង​ឧបករណ៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ភ្ជាប់​ទៅ​ការ​បញ្ចូល​ទូរទស្សន៍"</string>
     <string name="permdesc_bindTvInput" msgid="2371008331852001924">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុចប្រទាក់​កម្រិត​ខ្ពស់​នៃ​ការ​បញ្ចូល​ទូរទស្សន៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​​​ឧបករណ៍​​"</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​​​ឧបករណ៍"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"អនុញ្ញាត​​​ឲ្យ​ម្ចាស់​​​បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​ឧបករណ៍​សកម្ម​ចេញ​។ មិន​គួរ​ប្រើ​សម្រាប់​កម្មវិធី​​ធម្មតា​ទេ​។"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ប្ដូរ​ទិស​អេក្រង់"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"ឲ្យ​កម្មវិធី​ប្ដូរ​ការ​បង្វិល​អេក្រង់​នៅ​ពេល​ណា​មួយ។ មិន​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
@@ -422,9 +422,9 @@
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"ឲ្យ​កម្មវិធី​ស្នើ​​សញ្ញា​ដែល​បាន​ផ្ដល់​ត្រូវ​ផ្ញើ​ទៅ​ដំណើរការ​ស្ថិតស្ថេរ​​ទាំង​អស់។"</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"ធ្វើ​ឲ្យ​កម្មវិធី​ដំណើរការ​ជា​និច្ច"</string>
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"ឲ្យ​កម្មវិធី​ធ្វើជា​ផ្នែក​​ស្ថិតស្ថេរ​ដោយ​ខ្លួន​ឯង​ក្នុង​អង្គ​ចងចាំ។ វា​អាច​កំណត់​អង្គ​ចងចាំ​ដែល​អាច​ប្រើ​បាន​ចំពោះ​កម្មវិធី​ផ្សេងៗ​ ដោយ​ធ្វើឲ្យ​កុំព្យូទ័រ​បន្ទះ​យឺត។"</string>
-    <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"ឲ្យ​កម្មវិធី ធ្វើជា​ផ្នែក​អចិន្ត្រៃយ៍​នៃ​ខ្លួន​ក្នុង​អង្គ​ចងចាំ។ វា​អាច​កម្រិត​អង្គ​ចងចាំ​អាច​ប្រើ​បាន​ ដើម្បី​ធ្វើ​ឲ្យ​កម្មវិធី​ផ្សេង​ធ្វើ​ឲ្យ​ទូរស័ព្ទ​របស់​អ្នក​យឺត។​"</string>
+    <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"ឲ្យ​កម្មវិធី ធ្វើជា​ផ្នែក​អចិន្ត្រៃយ៍​នៃ​ខ្លួន​ក្នុង​អង្គ​ចងចាំ។ វា​អាច​កម្រិត​អង្គ​ចងចាំ​អាច​ប្រើ​បាន​ ដើម្បី​ធ្វើ​ឲ្យ​កម្មវិធី​ផ្សេង​ធ្វើ​ឲ្យ​ទូរស័ព្ទ​របស់​អ្នក​យឺត។"</string>
     <string name="permlab_deletePackages" msgid="184385129537705938">"លុប​កម្មវិធី"</string>
-    <string name="permdesc_deletePackages" msgid="7411480275167205081">"ឲ្យ​កម្មវិធី​លុប​កញ្ចប់ Android ។ កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា ដើម្បី​លុប​កម្មវិធី​សំខាន់​ៗ។ ​"</string>
+    <string name="permdesc_deletePackages" msgid="7411480275167205081">"ឲ្យ​កម្មវិធី​លុប​កញ្ចប់ Android ។ កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា ដើម្បី​លុប​កម្មវិធី​សំខាន់​ៗ។"</string>
     <string name="permlab_clearAppUserData" msgid="274109191845842756">"លុប​ទិន្នន័យ​របស់​​កម្មវិធី​ផ្សេង"</string>
     <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"ឲ្យ​កម្មវិធី​សម្អាត​ទិន្នន័យ​អ្នក​ប្រើ។"</string>
     <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"លុប​ឃ្លាំង​សម្ងាត់​កម្មវិធី​ផ្សេងៗ"</string>
@@ -475,7 +475,7 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"ឲ្យ​កម្មវិធី​កែ​ទិន្នន័យ​អំពី​ទំនាក់ទំនង​របស់​អ្នក​ដែល​បាន​រក្សាទុក​ក្នុង​កុំព្យូទ័រ​បន្ទះ រួមមាន​ប្រេកង់​​ដែល​អ្នក​បាន​ហៅ អ៊ីមែល ឬ​ទាក់ទង​តាម​វិធី​ផ្សេងៗ​ជា​មួយ​ទំនាក់ទំនង​ជាក់លាក់។ សិទ្ធិ​​នេះ​អនុញ្ញាត​ឲ្យ​​​កម្មវិធី​លុប​ទិន្នន័យ​ទំនាក់ទំនង​របស់​អ្នក។"</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"ឲ្យ​កម្មវិធី​កែ​ទិន្នន័យ​អំពី​ទំនាក់ទំនង​របស់​អ្នក​ដែល​បាន​រក្សាទុក​ក្នុង​ទូរស័ព្ទ​របស់​អ្នក រួមមាន​ប្រេកង់​ដែល​អ្នក​បាន​ហៅ អ៊ីមែល ឬ​បាន​ទាក់ទង​​តាម​វិធី​ផ្សេងៗ​ជា​មួយ​ទំនាក់​ទំនាក់​ជាក់លាក់។ សិទ្ធិ​នេះ​ឲ្យ​កម្មវិធី​លុប​ទិន្នន័យ​ទំនាក់ទំនង។"</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"អាន​​កំណត់​ហេតុ​​​ហៅ"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"ឲ្យ​កម្មវិធី​អាន​បញ្ជី​ហៅ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។ សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​កម្មវិធី​រក្សាទុក​ទិន្នន័យ​បញ្ជី​ហៅ​របស់​អ្នក ហើយ​កម្មវិធី​ព្យាបាទ​អាច​ចែករំលែក​ទិន្នន័យ​បញ្ជី​ហៅ​ដោយ​មិន​ឲ្យ​អ្នក​ដឹង។​"</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"ឲ្យ​កម្មវិធី​អាន​បញ្ជី​ហៅ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។ សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​កម្មវិធី​រក្សាទុក​ទិន្នន័យ​បញ្ជី​ហៅ​របស់​អ្នក ហើយ​កម្មវិធី​ព្យាបាទ​អាច​ចែករំលែក​ទិន្នន័យ​បញ្ជី​ហៅ​ដោយ​មិន​ឲ្យ​អ្នក​ដឹង។"</string>
     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"ឲ្យ​កម្មវិធី​អាន​​​បញ្ជី​ហៅ​ទូរស័ព្ទ​របស់​អ្នក រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។ សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​កម្មវិធី​រក្សាទុក​ទិន្នន័យ​បញ្ជី​ហៅ​របស់​អ្នក ហើយ​កម្មវិធី​ព្យាបាទ​អាច​ចែករំលែក​ទិន្នន័យ​បញ្ជី​ហៅ​ដោយ​មិន​ឲ្យ​អ្នកដឹង។"</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"សរសេរ​បញ្ជី​ហៅ"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"ឲ្យ​កម្មវិធី​កែ​បញ្ជី​ហៅ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក​រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។​កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា ដើម្បី​លុប ឬ​កែ​បញ្ជី​ហៅ​របស់​អ្នក។"</string>
@@ -609,7 +609,7 @@
     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"ឲ្យ​កម្មវិធី​កំណត់​ជំនួយ​ទំហំ​ផ្ទាំង​រូបភាព​ប្រព័ន្ធ។"</string>
     <string name="permlab_masterClear" msgid="2315750423139697397">"កំណត់​ប្រព័ន្ធ​ទៅ​លំនាំដើម​រោងចក្រ​ឡើងវិញ"</string>
     <string name="permdesc_masterClear" msgid="3665380492633910226">"ឲ្យ​កម្មវិធី​កំណត់​ប្រព័ន្ធ​​ដូច​ការ​កំណត់​ចេញ​ពី​រោងចក្រ​ឡើងវិញ​ពេញលេញ ដោយ​លុប​ទិន្នន័យ ការ​កំណត់​រចនាសម្ព័ន្ធ និង​កម្មវិធី​បាន​ដំឡើង។"</string>
-    <string name="permlab_setTime" msgid="2021614829591775646">"កំណត់​​ម៉ោង​"</string>
+    <string name="permlab_setTime" msgid="2021614829591775646">"កំណត់​​ម៉ោង"</string>
     <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"ឲ្យ​កម្មវិធី​ប្ដូរ​ម៉ោង​កុំព្យូទ័រ​បន្ទះ។"</string>
     <string name="permdesc_setTime" product="default" msgid="1855702730738020">"ឲ្យ​កម្មវិធី​ប្ដូរ​ម៉ោង​ទូរស័ព្ទ។"</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"កំណត់​តំបន់​ពេលវេលា"</string>
@@ -775,7 +775,7 @@
   <string-array name="organizationTypes">
     <item msgid="7546335612189115615">"កន្លែង​ធ្វើការ"</item>
     <item msgid="4378074129049520373">"ផ្សេងៗ"</item>
-    <item msgid="3455047468583965104">"តាម​តម្រូវ​ការ​"</item>
+    <item msgid="3455047468583965104">"តាម​តម្រូវ​ការ"</item>
   </string-array>
   <string-array name="imProtocols">
     <item msgid="8595261363518459565">"AIM"</item>
@@ -791,7 +791,7 @@
     <string name="phoneTypeHome" msgid="2570923463033985887">"ផ្ទះ"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"​ចល័ត"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"កន្លែង​ធ្វើការ"</string>
-    <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ទូរសារ​កន្លែង​ធ្វើការ​"</string>
+    <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ទូរសារ​កន្លែង​ធ្វើការ"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"ទូរសារ​ផ្ទះ"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"ភេយ័រ"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"ផ្សេងៗ"</string>
@@ -916,7 +916,7 @@
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"ព្យាយាម​លំនាំ​ច្រើន​ពេក"</string>
     <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"ដើម្បី​ដោះ​សោ ចូល​គណនី Google របស់​អ្នក។"</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ឈ្មោះ​អ្នក​ប្រើ (អ៊ីមែល​)"</string>
-    <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"ពាក្យសម្ងាត់​"</string>
+    <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"ពាក្យសម្ងាត់"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ចូល"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ។"</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"ភ្លេច​ឈ្មោះ​អ្នក​ប្រើ ឬ​ពាក្យ​សម្ងាត់​របស់​អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
@@ -961,7 +961,7 @@
     <string name="factorytest_failed" msgid="5410270329114212041">"បាន​បរាជ័យ​ក្នុង​ការ​សាកល្បង​រោងចក្រ"</string>
     <string name="factorytest_not_system" msgid="4435201656767276723">"សកម្មភាព FACTORY_TEST ត្រូវ​បាន​គាំទ្រ​សម្រាប់​តែ​កញ្ចប់​បាន​ដំឡើង​ក្នុង /system/app."</string>
     <string name="factorytest_no_action" msgid="872991874799998561">"រក​មិន​ឃើញ​កញ្ចប់​ដែល​ផ្ដល់​សកម្មភាព FACTORY_TEST ។"</string>
-    <string name="factorytest_reboot" msgid="6320168203050791643">"ចាប់​ផ្ដើម​ឡើង​វិញ​"</string>
+    <string name="factorytest_reboot" msgid="6320168203050791643">"ចាប់​ផ្ដើម​ឡើង​វិញ"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"ទំព័រ​មាន​ចំណងជើង \"<xliff:g id="TITLE">%s</xliff:g>\" សរសេរ៖"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"បញ្ជាក់​ការ​រុករក"</string>
@@ -1019,7 +1019,7 @@
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"ម៉ឺនុយ +"</string>
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"ដកឃ្លា"</string>
     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
-    <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"លុប​"</string>
+    <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"លុប"</string>
     <string name="search_go" msgid="8298016669822141719">"ស្វែងរក"</string>
     <string name="searchview_description_search" msgid="6749826639098512120">"ស្វែងរក"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"ស្វែងរក​សំណួរ"</string>
@@ -1103,18 +1103,18 @@
     <string name="preposition_for_date" msgid="9093949757757445117">"នៅ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"នៅ​ម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ក្នុង​ឆ្នាំ <xliff:g id="YEAR">%s</xliff:g>"</string>
-    <string name="day" msgid="8144195776058119424">"ថ្ងៃ​"</string>
+    <string name="day" msgid="8144195776058119424">"ថ្ងៃ"</string>
     <string name="days" msgid="4774547661021344602">"​ថ្ងៃ"</string>
     <string name="hour" msgid="2126771916426189481">"ម៉ោង"</string>
     <string name="hours" msgid="894424005266852993">"ម៉ោង"</string>
-    <string name="minute" msgid="9148878657703769868">"នាទី​"</string>
+    <string name="minute" msgid="9148878657703769868">"នាទី"</string>
     <string name="minutes" msgid="5646001005827034509">"នាទី"</string>
-    <string name="second" msgid="3184235808021478">"វិនាទី​"</string>
+    <string name="second" msgid="3184235808021478">"វិនាទី"</string>
     <string name="seconds" msgid="3161515347216589235">"វិនាទី"</string>
-    <string name="week" msgid="5617961537173061583">"សប្ដាហ៍​"</string>
-    <string name="weeks" msgid="6509623834583944518">"សប្ដាហ៍​"</string>
-    <string name="year" msgid="4001118221013892076">"ឆ្នាំ​"</string>
-    <string name="years" msgid="6881577717993213522">"ឆ្នាំ​"</string>
+    <string name="week" msgid="5617961537173061583">"សប្ដាហ៍"</string>
+    <string name="weeks" msgid="6509623834583944518">"សប្ដាហ៍"</string>
+    <string name="year" msgid="4001118221013892076">"ឆ្នាំ"</string>
+    <string name="years" msgid="6881577717993213522">"ឆ្នាំ"</string>
   <plurals name="duration_seconds">
     <item quantity="one" msgid="6962015528372969481">"1 វិនាទី"</item>
     <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
@@ -1130,12 +1130,12 @@
     <string name="VideoView_error_title" msgid="3534509135438353077">"បញ្ហា​វីដេអូ"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"វីដេអូ​នេះ​មិន​ត្រឹមត្រូវ​សម្រាប់​​ចរន្ត​ចូល​ឧបករណ៍​នេះ។"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"មិន​អាច​ចាក់​វីដេអូ​នេះ។"</string>
-    <string name="VideoView_error_button" msgid="2822238215100679592">"យល់​ព្រម​"</string>
+    <string name="VideoView_error_button" msgid="2822238215100679592">"យល់​ព្រម"</string>
     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="7245353528818587908">"រសៀល"</string>
     <string name="Noon" msgid="3342127745230013127">"រសៀល"</string>
     <string name="midnight" msgid="7166259508850457595">"កណ្ដាលអធ្រាត្រ"</string>
-    <string name="Midnight" msgid="5630806906897892201">"កណ្ដាល​អធ្រាត្រ​"</string>
+    <string name="Midnight" msgid="5630806906897892201">"កណ្ដាល​អធ្រាត្រ"</string>
     <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
     <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
     <string name="selectAll" msgid="6876518925844129331">"ជ្រើស​ទាំងអស់"</string>
@@ -1152,13 +1152,13 @@
     <string name="inputMethod" msgid="1653630062304567879">"វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"សកម្មភាព​អត្ថបទ"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"អស់​ទំហំ​ផ្ទុក"</string>
-    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារ​ប្រព័ន្ធ​មួយ​ចំនួន​អាច​មិន​ដំណើរការ​"</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារ​ប្រព័ន្ធ​មួយ​ចំនួន​អាច​មិន​ដំណើរការ"</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុង​ដំណើរការ"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"ប៉ះ​ ដើម្បី​មើល​ព័ត៌មាន​បន្ថែម ឬ​បញ្ឈប់​កម្មវិធី។"</string>
-    <string name="ok" msgid="5970060430562524910">"យល់​ព្រម​"</string>
-    <string name="cancel" msgid="6442560571259935130">"បោះ​បង់​"</string>
-    <string name="yes" msgid="5362982303337969312">"យល់​ព្រម​"</string>
-    <string name="no" msgid="5141531044935541497">"បោះ​បង់​"</string>
+    <string name="ok" msgid="5970060430562524910">"យល់​ព្រម"</string>
+    <string name="cancel" msgid="6442560571259935130">"បោះ​បង់"</string>
+    <string name="yes" msgid="5362982303337969312">"យល់​ព្រម"</string>
+    <string name="no" msgid="5141531044935541497">"បោះ​បង់"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ប្រយ័ត្ន"</string>
     <string name="loading" msgid="7933681260296021180">"កំពុង​ផ្ទុក..."</string>
     <string name="capital_on" msgid="1544682755514494298">"បើក"</string>
@@ -1167,7 +1167,7 @@
     <string name="whichHomeApplication" msgid="4616420172727326782">"ជ្រើស​កម្មវិធី​ដើម"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ប្រើ​តាម​លំនាំដើម​សម្រាប់​សកម្មភាព​នេះ។"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"សម្អាត​លំនាំដើម​ក្នុង​ការកំណត់​ប្រព័ន្ធ &gt; កម្មវិធី &gt; ទាញ​យក។"</string>
-    <string name="chooseActivity" msgid="7486876147751803333">"ជ្រើស​សកម្មភាព​​"</string>
+    <string name="chooseActivity" msgid="7486876147751803333">"ជ្រើស​សកម្មភាព"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"ជ្រើស​កម្មវិធី​សម្រាប់​ឧបករណ៍​យូអេសប៊ី"</string>
     <string name="noApplications" msgid="2991814273936504689">"គ្មាន​កម្មវិធី​អាច​អនុវត្ត​សកម្មភាព​នេះ។"</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
@@ -1178,7 +1178,7 @@
     <string name="anr_activity_process" msgid="5776209883299089767">"សកម្មភាព <xliff:g id="ACTIVITY">%1$s</xliff:g> មិន​ឆ្លើយតប។\n\nតើ​អ្នក​ចង់​បិទ​វា?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> មិន​ឆ្លើយតប។ តើ​អ្នក​ចង់​បិទ​វា?"</string>
     <string name="anr_process" msgid="6513209874880517125">"ដំណើរការ <xliff:g id="PROCESS">%1$s</xliff:g> មិន​ឆ្លើយតប។ \n\nតើ​អ្នក​ចង់​បិទ​វា​ឬ?"</string>
-    <string name="force_close" msgid="8346072094521265605">"យល់​ព្រម​"</string>
+    <string name="force_close" msgid="8346072094521265605">"យល់​ព្រម"</string>
     <string name="report" msgid="4060218260984795706">"រាយការណ៍"</string>
     <string name="wait" msgid="7147118217226317732">"រង់ចាំ"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"ទំព័រ​ក្លាយ​ជា​មិន​ឆ្លើយតប។\n\nតើ​អ្នក​​ចង់​បិទ​វា?"</string>
@@ -1260,19 +1260,19 @@
     <string name="sms_short_code_details" msgid="3492025719868078457"><font fgcolor="#ffffb060">"នេះ​អាច​កាត់​លុយ"</font>" លើ​គណនី​ចល័ត​របស់​អ្នក។"</string>
     <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"វា​នឹង​គិត​ថ្លៃ​សេវាកម្ម​លើ​គណនី​ចល័ត​របស់​អ្នក។"</font></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ផ្ញើ"</string>
-    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"បោះ​បង់​"</string>
+    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"បោះ​បង់"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"ចងចាំ​ជម្រើស​របស់​ខ្ញុំ"</string>
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"អ្នក​អាច​ប្ដូរ​វា​ពេល​ក្រោយ​ក្នុង​ការ​កំណត់ &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">"បាន​ដក​ស៊ីម​កាត​ចេញ"</string>
-    <string name="sim_removed_message" msgid="2333164559970958645">"បណ្ដាញ​ចល័ត​នឹង​ប្រើ​លែង​បាន​រហូត​ដល់​អ្នក​ចាប់ផ្ដើម​ជា​មួយ​ស៊ីម​កាត​ដែល​បា​បញ្ចូល​ត្រឹមត្រូវ។​"</string>
+    <string name="sim_removed_message" msgid="2333164559970958645">"បណ្ដាញ​ចល័ត​នឹង​ប្រើ​លែង​បាន​រហូត​ដល់​អ្នក​ចាប់ផ្ដើម​ជា​មួយ​ស៊ីម​កាត​ដែល​បា​បញ្ចូល​ត្រឹមត្រូវ។"</string>
     <string name="sim_done_button" msgid="827949989369963775">"រួចរាល់"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"បាន​បន្ថែម​ស៊ីម​កាត"</string>
     <string name="sim_added_message" msgid="6599945301141050216">"ចាប់ផ្ដើម​ឧបករណ៍​របស់​អ្នក​ឡើង​វិញ ដើម្បី​ចូល​ដំណើរការ​បណ្ដាញ​ចល័ត។"</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>
+    <string name="time_picker_dialog_title" msgid="8349362623068819295">"កំណត់​ម៉ោង"</string>
+    <string name="date_picker_dialog_title" msgid="5879450659453782278">"កំណត់​កាល​បរិច្ឆេទ"</string>
     <string name="date_time_set" msgid="5777075614321087758">"កំណត់"</string>
     <string name="date_time_done" msgid="2507683751759308828">"រួចរាល់"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"ថ្មី៖ "</font></string>
@@ -1350,7 +1350,7 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"ឲ្យ​កម្មវិធី​ដក​សេវាកម្ម​នៃ​កម្មវិធី​ផ្ទុក​​លំនាំដើម ដើម្បី​ចម្លង​មាតិកា។​ មិន​សម្រាប់​ប្រើ​ដោយ​កម្មវិធី​លំនាំដើម។"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"នាំ​ផ្លូវ​លទ្ធផល​មេឌៀ"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"ឲ្យ​កម្មវិធី​នាំ​ផ្លូវ​លទ្ធផល​មេឌៀ​ទៅ​ឧបករណ៍​​ខាង​ក្រៅ​ផ្សេង។"</string>
-    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"ចូល​ដំណើរការ​ឧបករណ៍​ផ្ទុក​សុវត្ថិភាព​"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"ចូល​ដំណើរការ​ឧបករណ៍​ផ្ទុក​សុវត្ថិភាព"</string>
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"ឲ្យ​កម្មវិធី​ចូល​​ការ​ផ្ទុក​មាន​សុវត្ថិភាព keguard ។"</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"ពិនិត្យ​ការ​បង្ហាញ និង​លាក់​ការ​ការពារ"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"ឲ្យ​កម្មវិធី​គ្រប់គ្រង keguard ។"</string>
@@ -1365,7 +1365,7 @@
     <string name="ime_action_go" msgid="8320845651737369027">"ទៅ"</string>
     <string name="ime_action_search" msgid="658110271822807811">"ស្វែងរក"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"ផ្ញើ"</string>
-    <string name="ime_action_next" msgid="3138843904009813834">"បន្ទាប់​"</string>
+    <string name="ime_action_next" msgid="3138843904009813834">"បន្ទាប់"</string>
     <string name="ime_action_done" msgid="8971516117910934605">"រួចរាល់"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"មុន"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"អនុវត្ត"</string>
@@ -1374,7 +1374,7 @@
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"កម្មវិធី​មួយ ឬ​ច្រើន​ដូច​ខាង​ក្រោម​ស្នើ​សិទ្ធិ ដើម្បី​ចូល​គណនី​របស់​អ្នក​ឥឡូវ និង​ពេល​អនាគត។"</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"តើ​អ្នក​ចង់​អនុញ្ញាត​សំណើ​នេះ?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"ស្នើ​ចូល"</string>
-    <string name="allow" msgid="7225948811296386551">"អនុញ្ញាត​"</string>
+    <string name="allow" msgid="7225948811296386551">"អនុញ្ញាត"</string>
     <string name="deny" msgid="2081879885755434506">"បដិសេធ"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"បាន​ស្នើ​សិទ្ធិ"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"បាន​ស្នើ​សិទ្ធិ\nសម្រាប់​គណនី <xliff:g id="ACCOUNT">%s</xliff:g> ។"</string>
@@ -1397,12 +1397,12 @@
     <string name="no_file_chosen" msgid="6363648562170759465">"គ្មាន​ឯកសារ​បាន​ជ្រើស"</string>
     <string name="reset" msgid="2448168080964209908">"កំណត់​ឡើងវិញ"</string>
     <string name="submit" msgid="1602335572089911941">"ដាក់​ស្នើ"</string>
-    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បាន​បើក​របៀប​រថយន្ត​"</string>
+    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បាន​បើក​របៀប​រថយន្ត"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"ប៉ះ​ ដើម្បី​ចេញ​ពី​របៀប​រថយន្ត​។"</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"ប៉ះ​ ដើម្បី​រៀបចំ។"</string>
     <string name="back_button_label" msgid="2300470004503343439">"ថយក្រោយ"</string>
-    <string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់​"</string>
+    <string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"រំលង"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"ការ​ប្រើ​ទិន្នន័យ​ចល័ត​ខ្ពស់"</string>
     <string name="throttle_warning_notification_message" msgid="3340822228599337743">"ប៉ះ​ ដើម្បី​​ស្វែងយល់​បន្ថែម​អំពី​ការ​ប្រើ​​​ទិន្នន័យ​ចល័ត​។"</string>
@@ -1428,7 +1428,7 @@
     <string name="media_shared" product="nosdcard" msgid="5830814349250834225">"ឧបករណ៍​ផ្ទុក​យូអេសប៊ី​បច្ចុប្បន្ន​កំពុង​ប្រើ​ដោយ​កុំព្យូទ័រ។"</string>
     <string name="media_shared" product="default" msgid="5706130568133540435">"បច្ចុប្បន្ន​កាត​អេសឌី​កំពុង​ប្រើ​ដោយ​កុំព្យូទ័រ"</string>
     <string name="media_unknown_state" msgid="729192782197290385">"មិន​ស្គាល់​ស្ថានភាព​មេឌៀ​ខាង​ក្រៅ។"</string>
-    <string name="share" msgid="1778686618230011964">"ចែក​រំលែក​"</string>
+    <string name="share" msgid="1778686618230011964">"ចែក​រំលែក"</string>
     <string name="find" msgid="4808270900322985960">"រក"</string>
     <string name="websearch" msgid="4337157977400211589">"ស្វែងរក​តាម​បណ្ដាញ"</string>
     <string name="find_next" msgid="5742124618942193978">"រក​បន្ទាប់"</string>
@@ -1444,7 +1444,7 @@
     <string name="sync_undo_deletes" msgid="2941317360600338602">"មិន​ធ្វើ​ការ​លុប​វិញ"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"មិន​ធ្វើអ្វី​ទេ​ឥឡូវ"</string>
     <string name="choose_account_label" msgid="5655203089746423927">"ជ្រើស​គណនី"</string>
-    <string name="add_account_label" msgid="2935267344849993553">"បន្ថែម​គណនី​ថ្មី​​"</string>
+    <string name="add_account_label" msgid="2935267344849993553">"បន្ថែម​គណនី​ថ្មី"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"បន្ថែម​គណនី"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"បង្កើន"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"បន្ថយ"</string>
@@ -1463,15 +1463,15 @@
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"បង្កើន​​ឆ្នាំ"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"បន្ថយ​ឆ្នាំ"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះ​បង់​"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះ​បង់"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"រួចរាល់"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ប្ដូរ​របៀប"</string>
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ជ្រើស​កម្មវិធី​​"</string>
+    <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ជ្រើស​កម្មវិធី"</string>
     <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"មិន​អាច​ចាប់ផ្ដើម <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <string name="shareactionprovider_share_with" msgid="806688056141131819">"ចែករំលែក​ជា​មួយ​"</string>
+    <string name="shareactionprovider_share_with" msgid="806688056141131819">"ចែករំលែក​ជា​មួយ"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"ចែក​រំលែក​ជា​មួយ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"គ្រប់គ្រង​ការ​រុញ។ ប៉ះ &amp; សង្កត់។"</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"អូស​ ដើម្បី​ដោះ​សោ។"</string>
@@ -1485,7 +1485,7 @@
     <string name="storage_internal" msgid="4891916833657929263">"ឧបករណ៍​ផ្ទុក​ខាង​ក្នុង"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"កាត​អេសឌី"</string>
     <string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍​ផ្ទុក​យូអេសប៊ី"</string>
-    <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល​"</string>
+    <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"ការព្រមាន​ប្រើ​ទិន្នន័យ"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"ប៉ះ ដើម្បី​មើល​ការ​ប្រើ និង​ការ​កំណត់។"</string>
     <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"បាន​បិទ​ទិន្នន័យ 2G​-3G"</string>
@@ -1542,7 +1542,7 @@
     <string name="media_route_status_available" msgid="6983258067194649391">"ទំនេរ"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"មិន​ទំនេរ"</string>
     <string name="media_route_status_in_use" msgid="4533786031090198063">"កំពុង​ប្រើ"</string>
-    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"អេក្រង់​ជាប់​"</string>
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"អេក្រង់​ជាប់"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"អេក្រង់ HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"#<xliff:g id="ID">%1$d</xliff:g> ត្រួត​គ្នា"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
@@ -1574,7 +1574,7 @@
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាម​លំនាំ​ច្រើន​ពេក"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"ដើម្បី​ដោះ​សោ ចូល​ក្នុង​គណនី Google ។"</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"ឈ្មោះ​អ្នក​ប្រើ (អ៊ី​ម៉ែ​ល​)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់​"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"ចូល"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ។"</string>
     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ភ្លេច​ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​របស់​អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
@@ -1683,7 +1683,7 @@
     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
     <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"​មិន​ស្គាល់​បញ្ឈរ"</string>
     <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"មិន​ស្គាល់​ទេសភាព"</string>
-    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"បាន​បោះ​បង់​"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"បាន​បោះ​បង់"</string>
     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"កំហុស​ក្នុង​ការ​សរសេរ​មាតិកា"</string>
     <string name="reason_unknown" msgid="6048913880184628119">"មិន​ស្គាល់"</string>
     <string name="reason_service_unavailable" msgid="7824008732243903268">"មិន​បា​ន​បើក​សេវាកម្ម​បោះពុម្ព"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 3b275a5..71f55fb 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1695,7 +1695,7 @@
     <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN ປະ​ຈຸ​ບັນ"</string>
     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"ລະຫັດ PIN ໃໝ່"</string>
     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"ຢືນຢັນລະຫັດ PIN ໃໝ່"</string>
-    <string name="restr_pin_create_pin" msgid="8017600000263450337">"ສ້າງ PIN ສໍາ​ລັບ​ການ​ປັບ​ປຸງ​ຂໍ້ຈໍາ​ກັດ​"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"ສ້າງ PIN ສໍາ​ລັບ​ການ​ປັບ​ປຸງ​ຂໍ້ຈໍາ​ກັດ"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN ບໍ່​ກົງກັນ. ລອງໃໝ່ອີກຄັ້ງ​."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ​ສັ້ນ​ເກີນ​ໄປ​. ຕ້ອງມີຢ່າງໜ້ອຍ 4 ຫຼັກ​."</string>
   <plurals name="restr_pin_countdown">
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4640f2a..d235eaa 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -187,7 +187,7 @@
     <string name="global_action_settings" msgid="1756531602592545966">"การตั้งค่า"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
-    <string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"ระบบแอนดรอยด์"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ส่วนตัว"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"ที่ทำงาน"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"บริการที่ต้องเสียค่าใช้จ่าย"</string>
@@ -424,7 +424,7 @@
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้แท็บเล็ตทำงานช้าลง"</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้โทรศัพท์ทำงานช้าลง"</string>
     <string name="permlab_deletePackages" msgid="184385129537705938">"ลบแอปพลิเคชัน"</string>
-    <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพ็กเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
+    <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพ็กเกจแอนดรอยด์แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
     <string name="permlab_clearAppUserData" msgid="274109191845842756">"ลบข้อมูลของแอปพลิเคชันอื่น"</string>
     <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"อนุญาตให้แอปพลิเคชันล้างข้อมูลผู้ใช้"</string>
     <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"ลบแคชของแอปพลิเคชันอื่น"</string>
@@ -432,7 +432,7 @@
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"วัดพื้นที่เก็บข้อมูลของแอปพลิเคชัน"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"อนุญาตให้แอปพลิเคชันเรียกดูรหัส ข้อมูล และขนาดแคชของตน"</string>
     <string name="permlab_installPackages" msgid="2199128482820306924">"ติดตั้งแอปพลิเคชันโดยตรง"</string>
-    <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพ็กเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
+    <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพ็กเกจแอนดรอยด์ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
     <string name="permlab_clearAppCache" msgid="7487279391723526815">"ลบข้อมูลแคชของแอปพลิเคชันทั้งหมด"</string>
     <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของแท็บเล็ต โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
     <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของโทรศัพท์ โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
@@ -1190,7 +1190,7 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"เปิดใช้งานอีกครั้งในการตั้งค่าระบบ &gt; แอปพลิเคชัน &gt; ดาวน์โหลด"</string>
     <string name="smv_application" msgid="3307209192155442829">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
     <string name="smv_process" msgid="5120397012047462446">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
-    <string name="android_upgrading_title" msgid="1584192285441405746">"กำลังอัปเกรด Android..."</string>
+    <string name="android_upgrading_title" msgid="1584192285441405746">"กำลังอัปเกรดแอนดรอยด์..."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"กำลังเพิ่มประสิทธิภาพแอปพลิเคชัน <xliff:g id="NUMBER_0">%1$d</xliff:g> จาก <xliff:g id="NUMBER_1">%2$d</xliff:g> รายการ"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"กำลังเริ่มต้นแอปพลิเคชัน"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"เสร็จสิ้นการบูต"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9eb6f74..0b72c2c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4780,6 +4780,18 @@
         <attr name="height" />
     </declare-styleable>
 
+    <!-- Defines the group used in Vector Drawables. -->
+    <declare-styleable name="VectorDrawableGroup">
+        <!-- The Name of this group -->
+        <attr name="name" />
+        <!-- The amount to rotate the group -->
+        <attr name="rotation" />
+        <!-- The X coordinate of the center of rotation of a group -->
+        <attr name="pivotX" />
+        <!-- The Y coordinate of the center of rotation of a group -->
+        <attr name="pivotY" />
+    </declare-styleable>
+
     <!-- Defines the path used in Vector Drawables. -->
     <declare-styleable name="VectorDrawablePath">
         <!-- The Name of this path -->
@@ -4788,12 +4800,6 @@
         <attr name="strokeWidth" format="float" />
         <!-- The opacity of a path stroke -->
         <attr name="strokeOpacity" format="float" />
-        <!-- The amount to rotate the path stroke -->
-        <attr name="rotation" />
-        <!-- The X coordinate of the center of rotation of a path -->
-        <attr name="pivotX" />
-        <!-- The Y coordinate of the center of rotation of a path -->
-        <attr name="pivotY" />
         <!-- The color to stroke the path if not defined implies no stroke-->
         <attr name="stroke" format="color" />
         <!-- The color to fill the path if not defined implies no fill-->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b1f256e..acfbe2d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -885,41 +885,57 @@
          be passed a persistable Bundle in their Intent.extras. -->
     <attr name="persistable" format="boolean" />
 
-    <!-- Specify whether this activity should always be launched in doc-centric mode. For
-         values other than <code>none</code> the activity must be defined with
-         {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
-         This attribute can be overridden by {@link
-         android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+    <!-- This attribute specifies that an activity shall become the root activity of a
+         new task each time it is launched. Using this attribute permits the user to
+         have multiple documents from the same applications appear in the recent tasks list.
 
-         <p>If this attribute is not specified, <code>none</code> will be used.
-         Note that this launch behavior can be changed in some ways at runtime
-         through the {@link android.content.Intent} flags
-         {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}. -->
+         <p>Such a document is any kind of item for which an application may want to
+         maintain multiple simultaneous instances. Examples might be text files, web
+         pages, spreadsheets, or emails. Each such document will be in a separate
+         task in the recent taskss list.
+
+         <p>This attribute is equivalent to adding the flag {@link
+         android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} to every Intent used to launch
+         the activity.
+
+         <p>The documentLaunchMode attribute may be assigned one of three values, "none",
+         "intoExisting" and "always", described in detail below. For values other than
+         <code>none</code> the activity must be defined with
+         {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
+         If this attribute is not specified, <code>none</code> will be used.
+         Note that <code>none</code> can be overridden at run time if the Intent used
+         to launch it contains the flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+         Similarly <code>intoExisting</code> will be overridden by the flag
+         {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} combined with
+         {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}. -->
     <attr name="documentLaunchMode">
         <!-- The default mode, which will create a new task only when
              {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
              Intent.FLAG_ACTIVITY_NEW_TASK} is set. -->
         <enum name="none" value="0" />
-        <!-- All tasks will be searched for a matching Intent. If one is found
-             That task will cleared and restarted with the root activity receiving a call
+        <!-- All tasks will be searched for one whose base Intent's ComponentName and
+             data URI match those of the launching Intent. If such a task is found
+             that task will be cleared and restarted with the root activity receiving a call
              to {@link android.app.Activity#onNewIntent Activity.onNewIntent}. If no
              such task is found a new task will be created.
-             This is the equivalent of with {@link
+             <p>This is the equivalent of launching an activity with {@link
              android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
-             without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
-             Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+             set and without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+             Intent.FLAG_ACTIVITY_MULTIPLE_TASK} set. -->
         <enum name="intoExisting" value="1" />
-        <!-- A new task rooted at this activity will be created.
-             This is the equivalent of with {@link
+        <!-- A new task rooted at this activity will be created. This will happen whether or
+             not there is an existing task whose ComponentName and data URI match
+             that of the launcing intent This is the equivalent of launching an activity
+             with {@link
              android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
-             paired with {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
-             Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+             and {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+             Intent.FLAG_ACTIVITY_MULTIPLE_TASK} both set. -->
         <enum name="always" value="2" />
     </attr>
 
-    <!-- Tasks launched by activities with this attribute will remain in the recent task
+    <!-- Tasks launched by activities with this attribute will remain in the recent tasks
          list until the last activity in the task is completed. When that happens the task
-         will be automatically removed from the recent task list.
+         will be automatically removed from the recent tasks list.
 
          This attribute is the equivalent of {@link
          android.content.Intent#FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5375c14..e9d8ccc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1538,9 +1538,6 @@
          -->
     <string-array translatable="false" name="config_globalActionsList">
         <item>power</item>
-        <item>airplane</item>
-        <item>bugreport</item>
-        <item>silent</item>
         <item>users</item>
     </string-array>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 38f00fe..657f614 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -202,9 +202,6 @@
     <!-- Default width for a textview error popup -->
     <dimen name="textview_error_popup_default_width">240dip</dimen>
 
-    <!-- Volume panel y offset -->
-    <dimen name="volume_panel_top">16dp</dimen>
-
     <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. -->
     <dimen name="default_app_widget_padding_left">8dp</dimen>
     <dimen name="default_app_widget_padding_top">8dp</dimen>
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index 53e97fd..2defee2 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -47,6 +47,10 @@
     <dimen name="text_size_menu_quantum">14sp</dimen>
     <dimen name="text_size_button_quantum">14sp</dimen>
 
+    <dimen name="text_size_large_quantum">22sp</dimen>
+    <dimen name="text_size_medium_quantum">18sp</dimen>
+    <dimen name="text_size_small_quantum">14sp</dimen>
+
     <dimen name="floating_window_z">16dp</dimen>
     <dimen name="floating_window_margin">32dp</dimen>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4a27ebe..1f4c88d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -231,14 +231,6 @@
         <item name="windowExitAnimation">@anim/fast_fade_out</item>
     </style>
 
-    <!-- Window animations for swipe-dismissable windows. {@hide} -->
-    <style name="Animation.SwipeDismiss">
-        <item name="taskOpenEnterAnimation">@anim/swipe_window_enter</item>
-        <item name="taskOpenExitAnimation">@anim/swipe_window_exit</item>
-        <item name="taskCloseEnterAnimation">@anim/swipe_window_enter</item>
-        <item name="taskCloseExitAnimation">@anim/swipe_window_exit</item>
-    </style>
-
     <!-- Status Bar Styles -->
     <style name="TextAppearance.StatusBar">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
@@ -277,37 +269,6 @@
         <item name="android:textColor">#CCCCCC</item>
     </style>
 
-    <style name="TextAppearance.StatusBar.Quantum">
-    </style>
-    <style name="TextAppearance.StatusBar.Quantum.EventContent">
-        <item name="android:textColor">#90000000</item>
-        <item name="android:textSize">@dimen/notification_text_size</item>
-    </style>
-    <style name="TextAppearance.StatusBar.Quantum.EventContent.Title">
-        <item name="android:textColor">#DD000000</item>
-        <item name="android:textSize">@dimen/notification_title_text_size</item>
-    </style>
-    <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2">
-        <item name="android:textSize">@dimen/notification_subtext_size</item>
-    </style>
-    <style name="TextAppearance.StatusBar.Quantum.EventContent.Info">
-        <item name="android:textSize">@dimen/notification_subtext_size</item>
-    </style>
-    <style name="TextAppearance.StatusBar.Quantum.EventContent.Time">
-        <item name="android:textSize">@dimen/notification_subtext_size</item>
-    </style>
-    <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis">
-        <item name="android:textColor">#66000000</item>
-    </style>
-    <style name="Widget.StatusBar.Quantum.ProgressBar"
-           parent="Widget.Quantum.Light.ProgressBar.Horizontal">
-        <item name="android:progressDrawable">@drawable/notification_quantum_media_progress</item>
-    </style>
-
-    <style name="Widget.StatusBar.Quantum.ProgressBar"
-           parent="Widget.Quantum.Light.ProgressBar.Horizontal">
-    </style>
-
     <style name="TextAppearance.Small.CalendarViewWeekDayView">
         <item name="android:textStyle">bold</item>
     </style>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 5bac1f9..0c854d3 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -14,6 +14,19 @@
      limitations under the License.
 -->
 <resources>
+    <style name="Animation.Micro"/>
+
+    <style name="Animation.Micro.Activity" parent="Animation.Holo.Activity">
+        <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
+        <item name="activityOpenExitAnimation">@null</item>
+        <item name="activityCloseEnterAnimation">@null</item>
+        <item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
+        <item name="taskOpenEnterAnimation">@anim/slide_in_micro</item>
+        <item name="taskOpenExitAnimation">@null</item>
+        <item name="taskCloseEnterAnimation">@null</item>
+        <item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
+    </style>
+
     <style name="AlertDialog.Micro" parent="AlertDialog.Holo.Light">
         <item name="fullDark">@null</item>
         <item name="topDark">@null</item>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index e528278..2e7a5b1 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -182,7 +182,10 @@
         <item name="textColorLink">?attr/textColorLinkInverse</item>
     </style>
 
-    <style name="TextAppearance.Quantum.Large" parent="TextAppearance.Quantum.Headline" />
+    <style name="TextAppearance.Quantum.Large">
+        <item name="textSize">@dimen/text_size_large_quantum</item>
+        <item name="textColor">?attr/textColorPrimary</item>
+    </style>
 
     <style name="TextAppearance.Quantum.Large.Inverse">
         <item name="textColor">?attr/textColorPrimaryInverse</item>
@@ -191,7 +194,10 @@
         <item name="textColorLink">?attr/textColorLinkInverse</item>
     </style>
 
-    <style name="TextAppearance.Quantum.Medium" parent="TextAppearance.Quantum.Body1" />
+    <style name="TextAppearance.Quantum.Medium">
+        <item name="textSize">@dimen/text_size_medium_quantum</item>
+        <item name="textColor">?attr/textColorSecondary</item>
+    </style>
 
     <style name="TextAppearance.Quantum.Medium.Inverse">
         <item name="textColor">?attr/textColorSecondaryInverse</item>
@@ -200,7 +206,10 @@
         <item name="textColorLink">?attr/textColorLinkInverse</item>
     </style>
 
-    <style name="TextAppearance.Quantum.Small" parent="TextAppearance.Quantum.Caption" />
+    <style name="TextAppearance.Quantum.Small">
+        <item name="textSize">@dimen/text_size_small_quantum</item>
+        <item name="textColor">?attr/textColorTertiary</item>
+    </style>
 
     <style name="TextAppearance.Quantum.Small.Inverse">
         <item name="textColor">?attr/textColorTertiaryInverse</item>
@@ -351,6 +360,38 @@
         <item name="textStyle">bold</item>
     </style>
 
+    <style name="TextAppearance.StatusBar.Quantum" />
+
+    <style name="TextAppearance.StatusBar.Quantum.EventContent">
+        <item name="android:textColor">#90000000</item>
+        <item name="android:textSize">@dimen/notification_text_size</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Quantum.EventContent.Title">
+        <item name="android:textColor">#DD000000</item>
+        <item name="android:textSize">@dimen/notification_title_text_size</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2">
+        <item name="android:textSize">@dimen/notification_subtext_size</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Quantum.EventContent.Info">
+        <item name="android:textSize">@dimen/notification_subtext_size</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Quantum.EventContent.Time">
+        <item name="android:textSize">@dimen/notification_subtext_size</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis">
+        <item name="android:textColor">#66000000</item>
+    </style>
+
+    <style name="Widget.StatusBar.Quantum.ProgressBar" parent="Widget.Quantum.Light.ProgressBar.Horizontal">
+        <item name="android:progressDrawable">@drawable/notification_quantum_media_progress</item>
+    </style>
+
     <!-- Widget Styles -->
 
     <style name="Quantum"/>
@@ -390,7 +431,7 @@
     </style>
 
     <style name="Widget.Quantum.Button.Toggle">
-        <item name="background">@drawable/btn_toggle_holo_dark</item>
+        <item name="background">@drawable/btn_toggle_quantum</item>
         <item name="textOn">@string/capital_on</item>
         <item name="textOff">@string/capital_off</item>
         <item name="textAppearance">?attr/textAppearanceSmall</item>
@@ -459,13 +500,13 @@
 
     <style name="Widget.Quantum.CompoundButton.Switch">
         <item name="track">@drawable/switch_track_quantum</item>
-        <item name="thumb">@drawable/switch_inner_quantum</item>
+        <item name="thumb">@drawable/switch_thumb_quantum_anim</item>
         <item name="splitTrack">true</item>
         <item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item>
         <item name="textOn"></item>
         <item name="textOff"></item>
-        <item name="switchMinWidth">72dip</item>
-        <item name="switchPadding">16dip</item>
+        <item name="switchMinWidth">4dip</item>
+        <item name="switchPadding">4dip</item>
         <item name="background">?attr/selectableItemBackground</item>
     </style>
 
@@ -579,7 +620,7 @@
         <item name="indeterminateOnly">false</item>
         <item name="progressDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
         <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
-        <item name="thumb">@drawable/scrubber_control_selector_quantum</item>
+        <item name="thumb">@drawable/scrubber_control_quantum_anim</item>
         <item name="splitTrack">true</item>
         <item name="focusable">true</item>
         <item name="paddingStart">16dip</item>
@@ -784,15 +825,7 @@
     <style name="Widget.Quantum.Light.Button.Borderless" parent="Widget.Quantum.Button.Borderless"/>
     <style name="Widget.Quantum.Light.Button.Borderless.Small" parent="Widget.Quantum.Button.Borderless.Small"/>
     <style name="Widget.Quantum.Light.Button.Inset" parent="Widget.Quantum.Button.Inset"/>
-
-    <style name="Widget.Quantum.Light.Button.Toggle">
-        <item name="background">@drawable/btn_toggle_holo_light</item>
-        <item name="textOn">@string/capital_on</item>
-        <item name="textOff">@string/capital_off</item>
-        <item name="textAppearance">?attr/textAppearanceSmall</item>
-        <item name="minHeight">48dip</item>
-    </style>
-
+    <style name="Widget.Quantum.Light.Button.Toggle" parent="Widget.Quantum.Button.Toggle" />
     <style name="Widget.Quantum.Light.ButtonBar" parent="Widget.Quantum.ButtonBar"/>
     <style name="Widget.Quantum.Light.ButtonBar.AlertDialog" parent="Widget.Quantum.ButtonBar.AlertDialog"/>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index dcff978..69f73e5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -69,8 +69,6 @@
   <java-symbol type="id" name="edittext_container" />
   <java-symbol type="id" name="enter_pin_section" />
   <java-symbol type="id" name="expand_activities_button" />
-  <java-symbol type="id" name="expand_button" />
-  <java-symbol type="id" name="expand_button_divider" />
   <java-symbol type="id" name="expires_on" />
   <java-symbol type="id" name="find_next" />
   <java-symbol type="id" name="find_prev" />
@@ -161,9 +159,7 @@
   <java-symbol type="id" name="share" />
   <java-symbol type="id" name="shortcut" />
   <java-symbol type="id" name="skip_button" />
-  <java-symbol type="id" name="slider_group" />
   <java-symbol type="id" name="split_action_bar" />
-  <java-symbol type="id" name="stream_icon" />
   <java-symbol type="id" name="submit_area" />
   <java-symbol type="id" name="switch_new" />
   <java-symbol type="id" name="switch_old" />
@@ -181,7 +177,6 @@
   <java-symbol type="id" name="topPanel" />
   <java-symbol type="id" name="up" />
   <java-symbol type="id" name="value" />
-  <java-symbol type="id" name="visible_panel" />
   <java-symbol type="id" name="websearch" />
   <java-symbol type="id" name="wifi_p2p_wps_pin" />
   <java-symbol type="id" name="year" />
@@ -343,7 +338,6 @@
   <java-symbol type="dimen" name="search_view_preferred_width" />
   <java-symbol type="dimen" name="textview_error_popup_default_width" />
   <java-symbol type="dimen" name="toast_y_offset" />
-  <java-symbol type="dimen" name="volume_panel_top" />
   <java-symbol type="dimen" name="action_bar_stacked_max_height" />
   <java-symbol type="dimen" name="action_bar_stacked_tab_max_width" />
   <java-symbol type="dimen" name="notification_text_size" />
@@ -1199,8 +1193,6 @@
   <java-symbol type="layout" name="time_picker_legacy" />
   <java-symbol type="layout" name="time_picker_dialog" />
   <java-symbol type="layout" name="transient_notification" />
-  <java-symbol type="layout" name="volume_adjust" />
-  <java-symbol type="layout" name="volume_adjust_item" />
   <java-symbol type="layout" name="voice_interaction_session" />
   <java-symbol type="layout" name="web_text_view_dropdown" />
   <java-symbol type="layout" name="webview_find" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index ebdab5b..7e0467b 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -19,15 +19,14 @@
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
         <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
         <item name="textViewStyle">@style/Widget.Micro.TextView</item>
-
         <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
-        <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
+        <item name="windowAnimationStyle">@style/Animation.Micro.Activity</item>
         <item name="windowBackground">@color/black</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
         <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
-	</style>
+    </style>
 
     <style name="Theme.Micro.Light" parent="Theme.Holo.Light.NoActionBar">
         <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
@@ -35,7 +34,7 @@
         <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
         <item name="textViewStyle">@style/Widget.Micro.TextView</item>
         <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
-        <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
+        <item name="windowAnimationStyle">@style/Animation.Micro.Activity</item>
         <item name="windowBackground">@color/white</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
new file mode 100644
index 0000000..d649154
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+
+## The application with a minimal main dex
+include $(CLEAR_VARS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyAndException
+
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+
+include $(BUILD_PACKAGE)
+
+$(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
+	echo "com/android/multidexlegacyandexception/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
new file mode 100644
index 0000000..7fff711
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.multidexlegacyandexception"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18"/>
+
+    <application
+        android:name="com.android.multidexlegacyandexception.TestApplication"
+        android:label="multidexlegacyandexception"
+        >
+        <activity
+            android:name="com.android.multidexlegacyandexception.MainActivity"
+            android:label="multidexlegacyandexception" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.multidexlegacyandexception"
+                     android:label="Test for MultiDexLegacyAndException" />
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/res/layout/activity_main.xml
new file mode 100644
index 0000000..37eb613
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/res/layout/activity_main.xml
@@ -0,0 +1,13 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    tools:context=".MainActivity" >
+
+    <TextView
+        android:id="@+id/label_nb"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/label_nb" />
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/res/values/strings.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/res/values/strings.xml
new file mode 100644
index 0000000..e56e049
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/res/values/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">MultidexLegacyAndException</string>
+    <string name="action_settings">Settings</string>
+    <string name="label_nb">Here\'s the count: </string>
+
+</resources>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/CaughtOnlyByIntermediateException.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/CaughtOnlyByIntermediateException.java
new file mode 100644
index 0000000..d6883ec
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/CaughtOnlyByIntermediateException.java
@@ -0,0 +1,21 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class CaughtOnlyByIntermediateException extends RuntimeException {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/CaughtOnlyException.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/CaughtOnlyException.java
new file mode 100644
index 0000000..4903e01
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/CaughtOnlyException.java
@@ -0,0 +1,21 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class CaughtOnlyException extends RuntimeException {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ClassInSecondaryDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ClassInSecondaryDex.java
new file mode 100644
index 0000000..b08a11a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ClassInSecondaryDex.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.multidexlegacyandexception;
+
+public class ClassInSecondaryDex {
+    private boolean condition;
+
+    public ClassInSecondaryDex(boolean condition) {
+        this.condition = condition;
+    }
+
+    public void canThrow1() throws ExceptionInMainDex, ExceptionInMainDex2,
+            ExceptionInSecondaryDexWithSuperInMain {
+        if (condition) {
+            throw new ExceptionInMainDex();
+        }
+    }
+
+    public void canThrow2() throws ExceptionInSecondaryDex, ExceptionInSecondaryDex2,
+            ExceptionInSecondaryDexWithSuperInMain {
+        if (condition) {
+            throw new ExceptionInSecondaryDex();
+        }
+    }
+
+    public static void canThrowAll(Throwable toThrow) throws Throwable {
+        if (toThrow != null) {
+            throw toThrow;
+        }
+    }
+
+    public int get1() {
+        try {
+            canThrow1();
+            canThrow2();
+            return 1;
+        } catch (ExceptionInMainDex e) {
+            return 10;
+        } catch (ExceptionInSecondaryDex e) {
+            return 11;
+        } catch (OutOfMemoryError e) {
+            return 12;
+        } catch (CaughtOnlyException e) {
+            return 17;
+        } catch (SuperExceptionInSecondaryDex|SuperExceptionInMainDex e) {
+            return 23;
+       }
+    }
+
+    public int get2() {
+        try {
+            canThrow2();
+            canThrow1();
+            return 1;
+        } catch (ExceptionInMainDex e) {
+            return 10;
+        } catch (ExceptionInSecondaryDex e) {
+            return 11;
+        } catch (OutOfMemoryError e) {
+            return 12;
+        } catch (CaughtOnlyException e) {
+            return 17;
+        } catch (SuperExceptionInSecondaryDex e) {
+            return 23;
+        } catch (SuperExceptionInMainDex e) {
+            return 27;
+       }
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInMainDex.java
new file mode 100644
index 0000000..7fc3d73
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInMainDex.java
@@ -0,0 +1,20 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class ExceptionInMainDex extends SuperExceptionInMainDex {
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInMainDex2.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInMainDex2.java
new file mode 100644
index 0000000..3fbeac6
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInMainDex2.java
@@ -0,0 +1,20 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class ExceptionInMainDex2 extends SuperExceptionInMainDex {
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDex.java
new file mode 100644
index 0000000..9401c05
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDex.java
@@ -0,0 +1,21 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class ExceptionInSecondaryDex extends SuperExceptionInSecondaryDex {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDex2.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDex2.java
new file mode 100644
index 0000000..d1aa103
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDex2.java
@@ -0,0 +1,21 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class ExceptionInSecondaryDex2 extends SuperExceptionInSecondaryDex {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDexWithSuperInMain.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDexWithSuperInMain.java
new file mode 100644
index 0000000..9327882
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/ExceptionInSecondaryDexWithSuperInMain.java
@@ -0,0 +1,21 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class ExceptionInSecondaryDexWithSuperInMain extends SuperExceptionInMainDex {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/IntermediateClass.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/IntermediateClass.java
new file mode 100644
index 0000000..dfdc4af
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/IntermediateClass.java
@@ -0,0 +1,107 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class IntermediateClass {
+
+    public static int get1(boolean condition) {
+        return new ClassInSecondaryDex(condition).get1();
+    }
+
+    public static int get2(boolean condition) {
+        return new ClassInSecondaryDex(condition).get2();
+    }
+
+    public static int get3(boolean condition) {
+        ClassInSecondaryDex thrower = new ClassInSecondaryDex(condition);
+        try {
+            thrower.canThrow2();
+            thrower.canThrow1();
+            return 1;
+        } catch (ExceptionInMainDex e) {
+            return 10;
+        } catch (ExceptionInSecondaryDex e) {
+            return 11;
+        } catch (ExceptionInMainDex2 e) {
+            return 10;
+        } catch (ExceptionInSecondaryDex2 e) {
+            return 11;
+        } catch (OutOfMemoryError e) {
+            return 12;
+        } catch (CaughtOnlyException e) {
+            return 17;
+        } catch (ExceptionInSecondaryDexWithSuperInMain e) {
+            return 39;
+        } catch (SuperExceptionInSecondaryDex|SuperExceptionInMainDex|CaughtOnlyByIntermediateException e) {
+            return 23;
+       }
+    }
+
+    public static int get4(boolean condition) {
+        ClassInSecondaryDex thrower = new ClassInSecondaryDex(condition);
+        try {
+            thrower.canThrow2();
+            thrower.canThrow1();
+            return 1;
+        } catch (ExceptionInSecondaryDexWithSuperInMain e) {
+            return 39;
+        } catch (ExceptionInSecondaryDex e) {
+            return 11;
+        } catch (ExceptionInSecondaryDex2 e) {
+            return 11;
+        } catch (OutOfMemoryError e) {
+            return 12;
+        } catch (ExceptionInMainDex2 e) {
+            return 10;
+        } catch (ExceptionInMainDex e) {
+            return 10;
+        } catch (CaughtOnlyException e) {
+            return 17;
+        } catch (SuperExceptionInSecondaryDex e) {
+        } catch (SuperExceptionInMainDex e) {
+        } catch (CaughtOnlyByIntermediateException e) {
+            return 35;
+        }
+        return 39;
+    }
+
+
+    public static int get5(Throwable thrown) {
+        try {
+            ClassInSecondaryDex.canThrowAll(thrown);
+            return 1;
+        } catch (ExceptionInMainDex e) {
+            return 10;
+        } catch (ExceptionInSecondaryDex e) {
+            return 11;
+        } catch (ExceptionInMainDex2 e) {
+            return 12;
+        } catch (ExceptionInSecondaryDex2 e) {
+            return 13;
+        } catch (OutOfMemoryError e) {
+            return 14;
+        } catch (CaughtOnlyException e) {
+            return 17;
+        } catch (ExceptionInSecondaryDexWithSuperInMain e) {
+            return 39;
+        } catch (SuperExceptionInSecondaryDex|SuperExceptionInMainDex|CaughtOnlyByIntermediateException e) {
+            return 23;
+       } catch (Throwable e) {
+            return 37;
+        }
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/MainActivity.java
new file mode 100644
index 0000000..dd2ce7a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/MainActivity.java
@@ -0,0 +1,44 @@
+/*
+ * 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.multidexlegacyandexception;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+    public MainActivity() {
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+    }
+
+    public int get1(boolean condition) {
+        return IntermediateClass.get1(condition);
+    }
+
+    public int get2(boolean condition) {
+        return IntermediateClass.get2(condition);
+    }
+    public int get3(boolean condition) {
+        return MiniIntermediateClass.get3(condition);
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/MiniIntermediateClass.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/MiniIntermediateClass.java
new file mode 100644
index 0000000..5957662
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/MiniIntermediateClass.java
@@ -0,0 +1,35 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class MiniIntermediateClass {
+
+    public static int get3(boolean condition) {
+        ClassInSecondaryDex thrower = new ClassInSecondaryDex(condition);
+        try {
+            thrower.canThrow2();
+            thrower.canThrow1();
+            return 1;
+        } catch (ExceptionInMainDex e) {
+            return 10;
+        } catch (ExceptionInSecondaryDex e) {
+            return 11;
+        } catch (SuperExceptionInSecondaryDex|SuperExceptionInMainDex e) {
+            return 23;
+        }
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/SuperExceptionInMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/SuperExceptionInMainDex.java
new file mode 100644
index 0000000..c94b30a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/SuperExceptionInMainDex.java
@@ -0,0 +1,21 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class SuperExceptionInMainDex extends Exception {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/SuperExceptionInSecondaryDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/SuperExceptionInSecondaryDex.java
new file mode 100644
index 0000000..6366fae
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/SuperExceptionInSecondaryDex.java
@@ -0,0 +1,21 @@
+/*
+ * 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.multidexlegacyandexception;
+
+public class SuperExceptionInSecondaryDex extends Exception {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.java
new file mode 100644
index 0000000..5e931bc
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.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 com.android.multidexlegacyandexception;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.multidexlegacyandexception/android.test.InstrumentationTestRunner
+</code>
+ */
+public class Test extends ActivityInstrumentationTestCase2<MainActivity> {
+    public Test() {
+        super(MainActivity.class);
+    }
+
+    public void testExceptionInMainDex() {
+        assertEquals(10, TestApplication.get(true));
+    }
+
+    public void testExceptionInSecondaryDex() {
+        assertEquals(10, getActivity().get1(true));
+        assertEquals(11, getActivity().get2(true));
+    }
+
+    public void testExceptionInIntermediate() {
+        assertEquals(11, IntermediateClass.get3(true));
+        assertEquals(11, MiniIntermediateClass.get3(true));
+        assertEquals(11, IntermediateClass.get4(true));
+        assertEquals(1, IntermediateClass.get5(null));
+        assertEquals(10, IntermediateClass.get5(new ExceptionInMainDex()));
+        assertEquals(11, IntermediateClass.get5(new ExceptionInSecondaryDex()));
+        assertEquals(12, IntermediateClass.get5(new ExceptionInMainDex2()));
+        assertEquals(13, IntermediateClass.get5(new ExceptionInSecondaryDex2()));
+        assertEquals(14, IntermediateClass.get5(new OutOfMemoryError()));
+        assertEquals(17, IntermediateClass.get5(new CaughtOnlyException()));
+        assertEquals(39, IntermediateClass.get5(new ExceptionInSecondaryDexWithSuperInMain()));
+        assertEquals(23, IntermediateClass.get5(new SuperExceptionInSecondaryDex()));
+        assertEquals(23, IntermediateClass.get5(new SuperExceptionInMainDex()));
+        assertEquals(23, IntermediateClass.get5(new CaughtOnlyByIntermediateException()));
+        assertEquals(37, IntermediateClass.get5(new ArrayIndexOutOfBoundsException()));
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
new file mode 100644
index 0000000..dece9a4
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
@@ -0,0 +1,45 @@
+/*
+ * 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.multidexlegacyandexception;
+
+import android.support.multidex.MultiDexApplication;
+
+public class TestApplication extends MultiDexApplication {
+
+    private static void canThrow1(boolean condition) throws ExceptionInMainDex {
+        if (condition) {
+            throw new ExceptionInMainDex();
+        }
+    }
+
+
+    public static int get(boolean condition) {
+        try {
+            canThrow1(condition);
+            return 1;
+        } catch (ExceptionInMainDex e) {
+            return 10;
+        } catch (OutOfMemoryError e) {
+            return 12;
+        } catch (CaughtOnlyException e) {
+            return 17;
+        } catch (SuperExceptionInMainDex e) {
+            return 27;
+      }
+    }
+
+}
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
index 459bed5..c0c20e2 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
@@ -132,6 +132,29 @@
         assertEquals(nextItem, nextIme);
     }
 
+    private void assertRotationOrder(final ControllerImpl controller,
+            final boolean onlyCurrentIme,
+            final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) {
+        final int N = expectedRotationOrderOfImeSubtypeList.length;
+        for (int i = 0; i < N; i++) {
+            final int currentIndex = i;
+            final int nextIndex = (currentIndex + 1) % N;
+            final ImeSubtypeListItem currentItem =
+                    expectedRotationOrderOfImeSubtypeList[currentIndex];
+            final ImeSubtypeListItem nextItem = expectedRotationOrderOfImeSubtypeList[nextIndex];
+            assertNextInputMethod(controller, onlyCurrentIme, currentItem, nextItem);
+        }
+    }
+
+    private void onUserAction(final ControllerImpl controller,
+            final ImeSubtypeListItem subtypeListItem) {
+        InputMethodSubtype subtype = null;
+        if (subtypeListItem.mSubtypeName != null) {
+            subtype = createDummySubtype(subtypeListItem.mSubtypeName.toString());
+        }
+        controller.onUserActionLocked(subtypeListItem.mImi, subtype);
+    }
+
     @SmallTest
     public void testControllerImpl() throws Exception {
         final List<ImeSubtypeListItem> disabledItems = createDisabledImeSubtypes();
@@ -152,33 +175,20 @@
         final ControllerImpl controller = new ControllerImpl(enabledItems);
 
         // switching-aware loop
-        assertNextInputMethod(controller, false /* onlyCurrentIme */,
-                latinIme_en_US, latinIme_fr);
-        assertNextInputMethod(controller, false /* onlyCurrentIme */,
-                latinIme_fr, japaneseIme_ja_JP);
-        assertNextInputMethod(controller, false /* onlyCurrentIme */,
-                japaneseIme_ja_JP, latinIme_en_US);
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                latinIme_en_US, latinIme_fr, japaneseIme_ja_JP);
 
         // switching-unaware loop
-        assertNextInputMethod(controller, false /* onlyCurrentIme */,
-                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi);
-        assertNextInputMethod(controller, false /* onlyCurrentIme */,
-                switchingUnawarelatinIme_hi, subtypeUnawareIme);
-        assertNextInputMethod(controller, false /* onlyCurrentIme */,
-                subtypeUnawareIme, switchUnawareJapaneseIme_ja_JP);
-        assertNextInputMethod(controller, false /* onlyCurrentIme */,
-                switchUnawareJapaneseIme_ja_JP, switchingUnawarelatinIme_en_UK);
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
+                switchUnawareJapaneseIme_ja_JP);
 
         // test onlyCurrentIme == true
-        assertNextInputMethod(controller, true /* onlyCurrentIme */,
+        assertRotationOrder(controller, true /* onlyCurrentIme */,
                 latinIme_en_US, latinIme_fr);
-        assertNextInputMethod(controller, true /* onlyCurrentIme */,
-                latinIme_fr, latinIme_en_US);
-        assertNextInputMethod(controller, true /* onlyCurrentIme */,
+        assertRotationOrder(controller, true /* onlyCurrentIme */,
                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi);
         assertNextInputMethod(controller, true /* onlyCurrentIme */,
-                switchingUnawarelatinIme_hi, switchingUnawarelatinIme_en_UK);
-        assertNextInputMethod(controller, true /* onlyCurrentIme */,
                 subtypeUnawareIme, null);
         assertNextInputMethod(controller, true /* onlyCurrentIme */,
                 japaneseIme_ja_JP, null);
@@ -203,4 +213,64 @@
         assertNextInputMethod(controller, true /* onlyCurrentIme */,
                 disabledSubtypeUnawareIme, null);
     }
- }
+
+    // This test is disabled until DynamicRotationList is enabled.
+    @SmallTest
+    public void DISABLED_testControllerImplWithUserAction() throws Exception {
+        final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes();
+        final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0);
+        final ImeSubtypeListItem latinIme_fr = enabledItems.get(1);
+        final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2);
+        final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3);
+        final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4);
+        final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5);
+        final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6);
+
+        final ControllerImpl controller = new ControllerImpl(enabledItems);
+
+        // === switching-aware loop ===
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                latinIme_en_US, latinIme_fr, japaneseIme_ja_JP);
+        // Then notify that a user did something for latinIme_fr.
+        onUserAction(controller, latinIme_fr);
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                latinIme_fr, latinIme_en_US, japaneseIme_ja_JP);
+        // Then notify that a user did something for latinIme_fr again.
+        onUserAction(controller, latinIme_fr);
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                latinIme_fr, latinIme_en_US, japaneseIme_ja_JP);
+        // Then notify that a user did something for japaneseIme_ja_JP.
+        onUserAction(controller, latinIme_fr);
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                japaneseIme_ja_JP, latinIme_fr, latinIme_en_US);
+        // Check onlyCurrentIme == true.
+        assertNextInputMethod(controller, true /* onlyCurrentIme */,
+                japaneseIme_ja_JP, null);
+        assertRotationOrder(controller, true /* onlyCurrentIme */,
+                latinIme_fr, latinIme_en_US);
+        assertRotationOrder(controller, true /* onlyCurrentIme */,
+                latinIme_en_US, latinIme_fr);
+
+        // === switching-unaware loop ===
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
+                switchUnawareJapaneseIme_ja_JP);
+        // User action should be ignored for switching unaware IMEs.
+        onUserAction(controller, switchingUnawarelatinIme_hi);
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
+                switchUnawareJapaneseIme_ja_JP);
+        // User action should be ignored for switching unaware IMEs.
+        onUserAction(controller, switchUnawareJapaneseIme_ja_JP);
+        assertRotationOrder(controller, false /* onlyCurrentIme */,
+                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
+                switchUnawareJapaneseIme_ja_JP);
+        // Check onlyCurrentIme == true.
+        assertRotationOrder(controller, true /* onlyCurrentIme */,
+                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi);
+        assertNextInputMethod(controller, true /* onlyCurrentIme */,
+                subtypeUnawareIme, null);
+        assertNextInputMethod(controller, true /* onlyCurrentIme */,
+                switchUnawareJapaneseIme_ja_JP, null);
+    }
+}
diff --git a/data/fonts/Roboto-Black.ttf b/data/fonts/Roboto-Black.ttf
index 18cf2ae..2cdbe43 100644
--- a/data/fonts/Roboto-Black.ttf
+++ b/data/fonts/Roboto-Black.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
index 7e43dd2..15c9b4e 100644
--- a/data/fonts/Roboto-Bold.ttf
+++ b/data/fonts/Roboto-Bold.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
index b8f3165..a0abf30 100644
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ b/data/fonts/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
index b84e93c..67b5394 100644
--- a/data/fonts/Roboto-Italic.ttf
+++ b/data/fonts/Roboto-Italic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf
index 46c6fbc..d9fb64a 100644
--- a/data/fonts/Roboto-Light.ttf
+++ b/data/fonts/Roboto-Light.ttf
Binary files differ
diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf
index e11331d..1fd1d31 100644
--- a/data/fonts/Roboto-LightItalic.ttf
+++ b/data/fonts/Roboto-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Medium.ttf b/data/fonts/Roboto-Medium.ttf
index 433bca4..c63c115 100644
--- a/data/fonts/Roboto-Medium.ttf
+++ b/data/fonts/Roboto-Medium.ttf
Binary files differ
diff --git a/data/fonts/Roboto-MediumItalic.ttf b/data/fonts/Roboto-MediumItalic.ttf
index 7166eb7..cd7c835 100644
--- a/data/fonts/Roboto-MediumItalic.ttf
+++ b/data/fonts/Roboto-MediumItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
index 7180d51f..9cb4a5a 100644
--- a/data/fonts/Roboto-Regular.ttf
+++ b/data/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf
index 9792ed1..f02f100 100644
--- a/data/fonts/Roboto-Thin.ttf
+++ b/data/fonts/Roboto-Thin.ttf
Binary files differ
diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf
index 5366fe5..12a2ce0 100644
--- a/data/fonts/Roboto-ThinItalic.ttf
+++ b/data/fonts/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf
index fe52e7d..1079af6 100644
--- a/data/fonts/RobotoCondensed-Bold.ttf
+++ b/data/fonts/RobotoCondensed-Bold.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf
index 2d29ffb..e7f13c2 100644
--- a/data/fonts/RobotoCondensed-BoldItalic.ttf
+++ b/data/fonts/RobotoCondensed-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf
index 1d7eb08..7fa04481 100644
--- a/data/fonts/RobotoCondensed-Italic.ttf
+++ b/data/fonts/RobotoCondensed-Italic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Light.ttf b/data/fonts/RobotoCondensed-Light.ttf
index 1209024..96b75dd 100644
--- a/data/fonts/RobotoCondensed-Light.ttf
+++ b/data/fonts/RobotoCondensed-Light.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-LightItalic.ttf b/data/fonts/RobotoCondensed-LightItalic.ttf
index ed1ccea..7a2c164 100644
--- a/data/fonts/RobotoCondensed-LightItalic.ttf
+++ b/data/fonts/RobotoCondensed-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf
index 4a9a6f9..734cc40 100644
--- a/data/fonts/RobotoCondensed-Regular.ttf
+++ b/data/fonts/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/docs/html/community/index.html b/docs/html/community/index.html
index eeb1c51..e3834ba 100644
--- a/docs/html/community/index.html
+++ b/docs/html/community/index.html
@@ -34,6 +34,9 @@
 </script>
 
 <style>
+#header {
+  padding: 2.2em 0 0.2em 0;
+}
 #header-wrap h1 {
   margin:0;
   padding:0;
diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
index 2116c0f..9b9f9a3 100644
--- a/docs/html/distribute/tools/promote/brand.jd
+++ b/docs/html/distribute/tools/promote/brand.jd
@@ -9,6 +9,11 @@
 promotional materials. You can use the icons and other assets on this page
 provided that you follow the guidelines.</p>
 
+<p>Use of the Android or Google Play brands must be reviewed by the Android
+Partner Marketing team.  Use the <a
+href="https://docs.google.com/forms/d/1YE5gZpAAcFKjYcUddCsK1Bv9a9Y-luaLVnkazVlaJ2w/viewform">Android and Google Play Brand Permissions Inquiry form</a> to submit your
+marketing for review.</p>
+
 <h2 id="brand-android">Android</h2>
 
  <p>The following are guidelines for the Android brand
@@ -29,10 +34,12 @@
         <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
         <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
       </ul>
-      <p>If used with your logo, "for Android" needs to be smaller in size than your logo.
+      <p>If used with your logo, "for Android" should be no larger than 90% of your logo’s size.
       First instance of this use should be followed by a TM symbol, "for Android&trade;".</p>
     </li>
-    <li>Android may be used as a descriptor, as long as it is followed by a proper generic term.
+    <li>Android may be used as a descriptor, as long as it is followed by a
+        proper generic term. (Think of "Android" as a term used in place of
+        "the Android platform.")
       <ul>
         <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
         <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
@@ -62,14 +69,14 @@
 
     <p>When using the Android Robot or any modification of it, proper attribution is
     required under the terms of the <a href="http://creativecommons.org/licenses/by/3.0/">Creative
-Commons Attribution</a> license:</p>
+    Commons Attribution 3.0</a> license:</p>
    
     <blockquote><em>The Android robot is reproduced or modified from work created and shared by Google and
 used according to terms described in the Creative Commons 3.0 Attribution License.</em></blockquote>
     
-    <p>You may not file trademark applications incorporating the Android robot logo or
-derivatives thereof. We want to ensure that the Android robot remains available
-for all to use.</p>
+    <p>You may not file trademark applications incorporating the Android robot
+    logo or derivatives thereof within your company logo or business name. We
+    want to ensure that the Android robot remains available for all to use.</p>
 
 
 <h4 style="clear:right">Android logo</h4>
@@ -78,12 +85,10 @@
   <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
 </div>
 
-<p>The Android logo may not be used. Nor can this be used with the Android robot.</p>
+<p>The Android logo may not be used.</p>
+
 <p>The custom typeface may not be used.</p>
 
-
-
-
 <h2 id="brand-google_play">Google Play</h2>
 
 
@@ -98,7 +103,7 @@
 <p>When referring to the mobile experience, use "Google Play" unless the text is clearly
 instructional for the user. For example, a marketing headline might read "Download our
 games on Google Play&trade;," but instructional text would read "Download our games using the Google
-Play&trade; Store app."
+Play&trade; store app."
 
  <p>Any use of the Google Play name or icon needs to include this
     attribution in your communication:</p>
@@ -111,16 +116,16 @@
     <p style="text-align:center">
        <a href="{@docRoot}images/brand/Google_Play_Store_48.png">48x48</a> |
        <a href="{@docRoot}images/brand/Google_Play_Store_96.png">96x96</a><br>
-       <a href="{@docRoot}downloads/brand/Google_Play_Store.ai">Illustrator (.ai)</a>
+       <a href="{@docRoot}images/brand/Google_Play_Store_600.png">600x576</a>
        </p>
   </div>
   
-<h4>Google Play Store icon</h4>
+<h4>Google Play store icon</h4>
 
-<p>You may use the Google Play Store icon, but you may not modify it.</p>
+<p>You may use the Google Play store icon, but you may not modify it.</p>
 
-<p>As mentioned above, when referring to the Google Play Store app in copy, use the full name:
-"Google Play Store." However, when labeling the Google Play Store icon directly, it's OK to use
+<p>As mentioned above, when referring to the Google Play store app in copy, use the full name:
+"Google Play store." However, when labeling the Google Play store icon directly, it's OK to use
 "Play Store" alone to accurately reflect the icon label as it appears on a device.</p>
 
         
@@ -140,9 +145,14 @@
        <a href="{@docRoot}images/brand/en_generic_rgb_wo_60.png">172x60</a></p>
   </div>
          
-  <p>The "Get it on Google Play" and "Android App on Google Play" logos are badges that you
-    can use on your website and promotional materials, to point to your products on Google
-    Play.</p>
+  <p>The "Get it on Google Play" and "Android App on Google Play" logos are
+    badges that you can use on your website and promotional materials, to point
+    to your products on Google Play. Additional Google Play badge formats and
+    badges for music, books, magazines, movies, and TV shows are also available.
+    Use the  <a
+    href="https://docs.google.com/forms/d/1YE5gZpAAcFKjYcUddCsK1Bv9a9Y-luaLVnkazVlaJ2w/viewform">Android
+    and Google Play Brand Permissions Inquiry form</a> to request
+    those badges.</p>
 
   <ul>
     <li>Don't modify the color, proportions, spacing, or any other aspect of the badge image.
@@ -163,7 +173,7 @@
   
   <p>To quickly create a badge that links to your apps on Google Play,
   use the <a
-  href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>
+  href="{@docRoot}distribute/tools/promote/badges.html">Google Play badge generator</a>
   (provides the badge in over 40 languages).</p>
   
   <p>To create your own size, download an Adobe&reg; Illustrator&reg; (.ai) file for the
@@ -171,25 +181,11 @@
   badge in over 40 languages</a>.</p>
     
   <p>For details on all the ways that you can link to your product details page in Google Play, 
-    see <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to your products</a></p>
+    see <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to your products</a>.</p>
 
+<h2 id="Marketing_Review">Marketing Reviews and Brand Inquiries</h2>
 
-
-<h2 id="Questions">Questions</h2>
-
-<p>To view our full guidelines or for any further brand usage questions, please contact our
-Android Partner Marketing team:</p>
-<ul>
-  <li>For North and South America, please contact <a
-  href="mailto:android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
-  >android-brand-approvals@google.com</a></li>
-
-  <li>For Europe and Emerging Markets, please contact <a
-  href="mailto:emea-android-brand@google.com?Subject=Brand%20Approval%20Questions"
-  >emea-android-brand@google.com</a></li>
-
-  <li>For Asia and Pacific-America, please contact <a
-  href="mailto:apac-android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
-  >apac-android-brand-approvals@google.com</a></li>
-</ul>
-
+<p>Use the <a
+href="https://docs.google.com/forms/d/1YE5gZpAAcFKjYcUddCsK1Bv9a9Y-luaLVnkazVlaJ2w/viewform">Android
+and Google Play Brand Permissions Inquiry form</a> to submit any marketing
+reviews or brand inquires. Typical response time is at least one week.</p>
diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
index 1d36430..f454c4e 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -820,7 +820,8 @@
     public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
     ...
 
-    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+        String key) {
         if (key.equals(KEY_PREF_SYNC_CONN)) {
             Preference connectionPref = findPreference(key);
             // Set summary to be the user-description for the selected value
@@ -863,7 +864,40 @@
 }
 </pre>
 
+<p class="caution"><strong>Caution:</strong> When you call {@link
+android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
+registerOnSharedPreferenceChangeListener()}, the preference manager does not
+currently store a strong reference to the listener. You must store a strong
+reference to the listener, or it will be susceptible to garbage collection. We
+recommend you keep a reference to the listener in the instance data of an object
+that will exist as long as you need the listener.</p>
 
+<p>For example, in the following code, the caller does not keep a reference to
+the listener. As a result, the listener will be subject to garbage collection,
+and it will fail at some indeterminate time in the future:</p>
+
+<pre>
+prefs.registerOnSharedPreferenceChangeListener(
+  // Bad! The listener is subject to garbage collection!
+  new SharedPreferences.OnSharedPreferenceChangeListener() {
+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+    // listener implementation
+  }
+});
+</pre>
+
+<p>Instead, store a reference to the listener in an instance data field of an
+object that will exist as long as the listener is needed:</p>
+
+<pre>
+SharedPreferences.OnSharedPreferenceChangeListener listener =
+    new SharedPreferences.OnSharedPreferenceChangeListener() {
+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+    // listener implementation
+  }
+};
+prefs.registerOnSharedPreferenceChangeListener(listener);
+</pre>
 
 <h2 id="NetworkUsage">Managing Network Usage</h2>
 
@@ -1142,13 +1176,15 @@
     final Parcelable superState = super.onSaveInstanceState();
     // Check whether this Preference is persistent (continually saved)
     if (isPersistent()) {
-        // No need to save instance state since it's persistent, use superclass state
+        // No need to save instance state since it's persistent,
+        // use superclass state
         return superState;
     }
 
     // Create instance of custom BaseSavedState
     final SavedState myState = new SavedState(superState);
-    // Set the state's value with the class member that holds current setting value
+    // Set the state's value with the class member that holds current
+    // setting value
     myState.value = mNewValue;
     return myState;
 }
diff --git a/docs/html/images/brand/Google_Play_Store_600.png b/docs/html/images/brand/Google_Play_Store_600.png
new file mode 100644
index 0000000..f748652
--- /dev/null
+++ b/docs/html/images/brand/Google_Play_Store_600.png
Binary files differ
diff --git a/docs/image_sources/brand/Google_Play_Store.ai b/docs/image_sources/brand/Google_Play_Store.ai
deleted file mode 100644
index 51f07c6..0000000
--- a/docs/image_sources/brand/Google_Play_Store.ai
+++ /dev/null
Binary files differ
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index a759a79..210ea86b 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -31,7 +31,6 @@
 
     public FontFamily() {
         mNativePtr = nCreateFamily();
-        mNativePtr = nCreateFamily();
         if (mNativePtr == 0) {
             throw new RuntimeException();
         }
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 64451c4..b7613fb 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -66,6 +66,9 @@
     static Map<String, Typeface> sSystemFontMap;
     static FontFamily[] sFallbackFonts;
 
+    static final String SYSTEM_FONTS_CONFIG = "system_fonts.xml";
+    static final String FALLBACK_FONTS_CONFIG = "fallback_fonts.xml";
+
     /**
      * @hide
      */
@@ -249,10 +252,16 @@
         return fontFamily;
     }
 
-    static {
+    /*
+     * (non-Javadoc)
+     *
+     * This should only be called once, from the static class initializer block.
+     */
+    private static void init() {
         // Load font config and initialize Minikin state
-        String systemConfigFilename = "/system/etc/system_fonts.xml";
-        String configFilename = "/system/etc/fallback_fonts.xml";
+        File systemFontConfigLocation = getSystemFontConfigLocation();
+        File systemConfigFilename = new File(systemFontConfigLocation, SYSTEM_FONTS_CONFIG);
+        File configFilename = new File(systemFontConfigLocation, FALLBACK_FONTS_CONFIG);
         try {
             // TODO: throws an exception non-Minikin builds, to fail early;
             // remove when Minikin-only
@@ -301,7 +310,10 @@
         } catch (XmlPullParserException e) {
             Log.e(TAG, "XML parse exception for " + configFilename);
         }
+    }
 
+    static {
+        init();
         // Set up defaults and typefaces exposed in public API
         DEFAULT         = create((String) null, 0);
         DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
@@ -315,6 +327,11 @@
             create((String) null, Typeface.ITALIC),
             create((String) null, Typeface.BOLD_ITALIC),
         };
+
+    }
+
+    private static File getSystemFontConfigLocation() {
+        return new File("/system/etc/");
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 46e3401..42872e9 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -80,6 +80,22 @@
         this(null, null);
     }
 
+    @Override
+    public boolean setVisible(boolean visible, boolean restart) {
+        final boolean changed = super.setVisible(visible, restart);
+        if (mAnim != null) {
+            if (visible) {
+                if (changed || restart) {
+                    // TODO: Should this support restart?
+                    mAnim.end();
+                }
+            } else {
+                mAnim.end();
+            }
+        }
+        return changed;
+    }
+
     /**
      * Add a new drawable to the set of keyframes.
      *
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index f3fcf2c..c95ac82 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -25,6 +25,7 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
@@ -92,6 +93,9 @@
     private int mBitmapWidth;
     private int mBitmapHeight;
 
+    /** Optical insets due to gravity. */
+    private Insets mOpticalInsets = null;
+
     // Mirroring matrix for using with Shaders
     private Matrix mMirrorMatrix;
 
@@ -456,9 +460,9 @@
 
     @Override
     protected void onBoundsChange(Rect bounds) {
-        super.onBoundsChange(bounds);
         mApplyGravity = true;
-        Shader shader = mBitmapState.mPaint.getShader();
+
+        final Shader shader = mBitmapState.mPaint.getShader();
         if (shader != null) {
             if (needMirroring()) {
                 updateMirrorMatrix(bounds.right - bounds.left);
@@ -517,9 +521,7 @@
         final boolean needMirroring = needMirroring();
         if (shader == null) {
             if (mApplyGravity) {
-                final int layoutDirection = getLayoutDirection();
-                Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight,
-                        getBounds(), mDstRect, layoutDirection);
+                applyGravity();
                 mApplyGravity = false;
             }
 
@@ -564,6 +566,31 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public Insets getOpticalInsets() {
+        if (mApplyGravity && mBitmapState.mPaint.getShader() == null) {
+            applyGravity();
+            mApplyGravity = false;
+        }
+        return mOpticalInsets == null ? Insets.NONE : mOpticalInsets;
+    }
+
+    private void applyGravity() {
+        final Rect bounds = getBounds();
+        final int layoutDirection = getLayoutDirection();
+        Gravity.apply(mBitmapState.mGravity, mBitmapWidth, mBitmapHeight,
+                bounds, mDstRect, layoutDirection);
+
+        final int left = mDstRect.left - bounds.left;
+        final int top = mDstRect.top - bounds.top;
+        final int right = bounds.right - mDstRect.right;
+        final int bottom = bounds.bottom - mDstRect.bottom;
+        mOpticalInsets = Insets.of(left, top, right, bottom);
+    }
+
     @Override
     public void setAlpha(int alpha) {
         final int oldAlpha = mBitmapState.mPaint.getAlpha();
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 04373d4..2aef39f 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -187,6 +187,9 @@
         }
         if (mCurrDrawable != null) {
             mCurrDrawable.setBounds(bounds);
+
+            // Must obtain optical insets after setting bounds.
+            mInsets = mCurrDrawable.getOpticalInsets();
         }
     }
 
@@ -385,7 +388,6 @@
             mCurrDrawable = d;
             mCurIndex = idx;
             if (d != null) {
-                mInsets = d.getOpticalInsets();
                 d.mutate();
                 if (mDrawableContainerState.mEnterFadeDuration > 0) {
                     mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
@@ -402,6 +404,9 @@
                 d.setBounds(getBounds());
                 d.setLayoutDirection(getLayoutDirection());
                 d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
+
+                // Must obtain optical insets after setting bounds.
+                mInsets = d.getOpticalInsets();
             } else {
                 mInsets = Insets.NONE;
             }
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index e3ed75e..b85e85c 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -39,7 +39,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashMap;
 
 /**
@@ -58,9 +57,10 @@
  * <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>
+ * <dt><code>&lt;group></code></dt>
+ * <dd>Defines a group of paths or subgroups, plus transformation information.</dd>
  * <dt><code>&lt;path></code></dt>
- * <dd>Defines paths to be drawn. Multiple paths can be defined in one xml file.
- * The paths are drawn in the order of their definition order.
+ * <dd>Defines paths to be drawn.
  * <dl>
  * <dt><code>android:name</code>
  * <dd>Defines the name of the path.</dd></dt>
@@ -107,6 +107,7 @@
 
     private static final String SHAPE_SIZE = "size";
     private static final String SHAPE_VIEWPORT = "viewport";
+    private static final String SHAPE_GROUP = "group";
     private static final String SHAPE_PATH = "path";
     private static final String SHAPE_VECTOR = "vector";
 
@@ -159,7 +160,8 @@
 
     @Override
     public void setColorFilter(ColorFilter colorFilter) {
-        // TODO: support color filter
+        mVectorState.mVPathRenderer.setColorFilter(colorFilter);
+        invalidateSelf();
     }
 
     @Override
@@ -264,6 +266,7 @@
 
         boolean noSizeTag = true;
         boolean noViewportTag = true;
+        boolean noGroupTag = true;
         boolean noPathTag = true;
 
         VGroup currentGroup = new VGroup();
@@ -283,12 +286,21 @@
                 } else if (SHAPE_VIEWPORT.equals(tagName)) {
                     pathRenderer.parseViewport(res, attrs);
                     noViewportTag = false;
+                } else if (SHAPE_GROUP.equals(tagName)) {
+                    currentGroup = new VGroup();
+                    currentGroup.inflate(res, attrs, theme);
+                    pathRenderer.mGroupList.add(currentGroup);
+                    noGroupTag = false;
                 }
             }
 
             eventType = parser.next();
         }
 
+        if (noGroupTag && !noPathTag) {
+            pathRenderer.mGroupList.add(currentGroup);
+        }
+
         if (noSizeTag || noViewportTag || noPathTag) {
             final StringBuffer tag = new StringBuffer();
 
@@ -313,9 +325,6 @@
             throw new XmlPullParserException("no " + tag + " defined");
         }
 
-        pathRenderer.mCurrentGroup = currentGroup;
-        // post parse cleanup
-        pathRenderer.parseFinish();
         return pathRenderer;
     }
 
@@ -362,29 +371,23 @@
         private final Path mRenderPath = new Path();
         private final Matrix mMatrix = new Matrix();
 
-        private VPath[] mCurrentPaths;
         private Paint mStrokePaint;
         private Paint mFillPaint;
+        private ColorFilter mColorFilter;
         private PathMeasure mPathMeasure;
 
-        private VGroup mCurrentGroup = new VGroup();
+        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
 
-        float mBaseWidth = 1;
-        float mBaseHeight = 1;
-        float mViewportWidth;
-        float mViewportHeight;
+        float mBaseWidth = 0;
+        float mBaseHeight = 0;
+        float mViewportWidth = 0;
+        float mViewportHeight = 0;
 
         public VPathRenderer() {
         }
 
         public VPathRenderer(VPathRenderer copy) {
-            mCurrentGroup = copy.mCurrentGroup;
-            if (copy.mCurrentPaths != null) {
-                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
-                for (int i = 0; i < mCurrentPaths.length; i++) {
-                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
-                }
-            }
+            mGroupList.addAll(copy.mGroupList);
 
             mBaseWidth = copy.mBaseWidth;
             mBaseHeight = copy.mBaseHeight;
@@ -393,147 +396,175 @@
         }
 
         public boolean canApplyTheme() {
-            final ArrayList<VPath> paths = mCurrentGroup.mVGList;
-            for (int j = paths.size() - 1; j >= 0; j--) {
-                final VPath path = paths.get(j);
-                if (path.canApplyTheme()) {
-                    return true;
+            final ArrayList<VGroup> groups = mGroupList;
+            for (int i = groups.size() - 1; i >= 0; i--) {
+                final ArrayList<VPath> paths = groups.get(i).mVGList;
+                for (int j = paths.size() - 1; j >= 0; j--) {
+                    final VPath path = paths.get(j);
+                    if (path.canApplyTheme()) {
+                        return true;
+                    }
                 }
             }
+
             return false;
         }
 
         public void applyTheme(Theme t) {
-            final ArrayList<VPath> paths = mCurrentGroup.mVGList;
-            for (int j = paths.size() - 1; j >= 0; j--) {
-                final VPath path = paths.get(j);
-                if (path.canApplyTheme()) {
-                    path.applyTheme(t);
+            final ArrayList<VGroup> groups = mGroupList;
+            for (int i = groups.size() - 1; i >= 0; i--) {
+                VGroup currentGroup = groups.get(i);
+                currentGroup.applyTheme(t);
+                final ArrayList<VPath> paths = currentGroup.mVGList;
+                for (int j = paths.size() - 1; j >= 0; j--) {
+                    final VPath path = paths.get(j);
+                    if (path.canApplyTheme()) {
+                        path.applyTheme(t);
+                    }
                 }
             }
         }
 
+        public void setColorFilter(ColorFilter colorFilter) {
+            mColorFilter = colorFilter;
+
+            if (mFillPaint != null) {
+                mFillPaint.setColorFilter(colorFilter);
+            }
+
+            if (mStrokePaint != null) {
+                mStrokePaint.setColorFilter(colorFilter);
+            }
+
+        }
+
         public void draw(Canvas canvas, int w, int h) {
-            if (mCurrentPaths == null) {
-                Log.e(LOGTAG,"mCurrentPaths == null");
+            if (mGroupList == null || mGroupList.size() == 0) {
+                Log.e(LOGTAG,"There is no group to draw");
                 return;
             }
 
-            for (int i = 0; i < mCurrentPaths.length; i++) {
-                if (mCurrentPaths[i] != null) {
-                    drawPath(mCurrentPaths[i], canvas, w, h);
+            for (int i = 0; i < mGroupList.size(); i++) {
+                VGroup currentGroup = mGroupList.get(i);
+                if (currentGroup != null) {
+                    drawPath(currentGroup, canvas, w, h);
                 }
             }
         }
 
-        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
+        private void drawPath(VGroup vGroup, Canvas canvas, int w, int h) {
             final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
 
-            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();
             mMatrix.reset();
 
-            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
+            mMatrix.postRotate(vGroup.mRotate, vGroup.mPivotX, vGroup.mPivotY);
             mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
             mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
 
-            mRenderPath.addPath(path, mMatrix);
+            ArrayList<VPath> paths = vGroup.getPaths();
+            for (int i = 0; i < paths.size(); i++) {
+                VPath vPath = paths.get(i);
+                vPath.toPath(mPath);
+                final Path path = mPath;
 
-            if (vPath.mClip) {
-                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
-            }
+                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 (vPath.mFillColor != 0) {
-                if (mFillPaint == null) {
-                    mFillPaint = new Paint();
-                    mFillPaint.setStyle(Paint.Style.FILL);
-                    mFillPaint.setAntiAlias(true);
+                    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
                 }
 
-                mFillPaint.setColor(vPath.mFillColor);
-                canvas.drawPath(mRenderPath, mFillPaint);
-            }
+                mRenderPath.reset();
 
-            if (vPath.mStrokeColor != 0) {
-                if (mStrokePaint == null) {
-                    mStrokePaint = new Paint();
-                    mStrokePaint.setStyle(Paint.Style.STROKE);
-                    mStrokePaint.setAntiAlias(true);
+                mRenderPath.addPath(path, mMatrix);
+
+                if (vPath.mClip) {
+                    canvas.clipPath(mRenderPath, Region.Op.REPLACE);
                 }
 
-                final Paint strokePaint = mStrokePaint;
-                if (vPath.mStrokeLineJoin != null) {
-                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
+                if (vPath.mFillColor != 0) {
+                    if (mFillPaint == null) {
+                        mFillPaint = new Paint();
+                        mFillPaint.setColorFilter(mColorFilter);
+                        mFillPaint.setStyle(Paint.Style.FILL);
+                        mFillPaint.setAntiAlias(true);
+                    }
+
+                    mFillPaint.setColor(vPath.mFillColor);
+                    canvas.drawPath(mRenderPath, mFillPaint);
                 }
 
-                if (vPath.mStrokeLineCap != null) {
-                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
+                if (vPath.mStrokeColor != 0) {
+                    if (mStrokePaint == null) {
+                        mStrokePaint = new Paint();
+                        mStrokePaint.setColorFilter(mColorFilter);
+                        mStrokePaint.setStyle(Paint.Style.STROKE);
+                        mStrokePaint.setAntiAlias(true);
+                    }
+
+                    final Paint strokePaint = mStrokePaint;
+                    if (vPath.mStrokeLineJoin != null) {
+                        strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
+                    }
+
+                    if (vPath.mStrokeLineCap != null) {
+                        strokePaint.setStrokeCap(vPath.mStrokeLineCap);
+                    }
+
+                    strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
+                    strokePaint.setColor(vPath.mStrokeColor);
+                    strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
+                    canvas.drawPath(mRenderPath, strokePaint);
                 }
-
-                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
-                strokePaint.setColor(vPath.mStrokeColor);
-                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
-                canvas.drawPath(mRenderPath, strokePaint);
-            }
-        }
-
-        /**
-         * Build the "current" path based on the current group
-         * TODO: improve memory use & performance or move to C++
-         */
-        public void parseFinish() {
-            final Collection<VPath> paths = mCurrentGroup.getPaths();
-            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
-            for (int i = 0; i < mCurrentPaths.length; i++) {
-                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
             }
         }
 
         private void parseViewport(Resources r, AttributeSet attrs)
                 throws XmlPullParserException {
             final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
-            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
-            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
-            if (mViewportWidth == 0 || mViewportHeight == 0) {
-                throw new XmlPullParserException(a.getPositionDescription()+
-                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
+            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);
-            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
-            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
-            if (mBaseWidth == 0 || mBaseHeight == 0) {
-                throw new XmlPullParserException(a.getPositionDescription()+
-                        "<size> tag requires width & height to be set");
+            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();
         }
 
@@ -543,17 +574,60 @@
         private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
         private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
 
+        private float mRotate = 0;
+        private float mPivotX = 0;
+        private float mPivotY = 0;
+
+        private int[] mThemeAttrs;
+
         public void add(VPath path) {
             String id = path.getID();
             mVGPathMap.put(id, path);
             mVGList.add(path);
          }
 
+        public void applyTheme(Theme t) {
+            if (mThemeAttrs == null) {
+                return;
+            }
+
+            final TypedArray a = t.resolveAttributes(
+                    mThemeAttrs, R.styleable.VectorDrawablePath);
+
+            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
+            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
+            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
+            a.recycle();
+        }
+
+        public void inflate(Resources res, AttributeSet attrs, Theme theme) {
+            final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup);
+            final int[] themeAttrs = a.extractThemeAttrs();
+
+            mThemeAttrs = themeAttrs;
+            // NOTE: The set of attributes loaded here MUST match the
+            // set of attributes loaded in applyTheme.
+
+            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) {
+                mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
+            }
+
+            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) {
+                mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
+            }
+
+            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) {
+                mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
+            }
+
+            a.recycle();
+        }
+
         /**
          * Must return in order of adding
          * @return ordered list of paths
          */
-        public Collection<VPath> getPaths() {
+        public ArrayList<VPath> getPaths() {
             return mVGList;
         }
 
@@ -572,10 +646,6 @@
         int mFillRule;
         float mFillOpacity = Float.NaN;
 
-        float mRotate = 0;
-        float mPivotX = 0;
-        float mPivotY = 0;
-
         float mTrimPathStart = 0;
         float mTrimPathEnd = 1;
         float mTrimPathOffset = 0;
@@ -587,18 +657,11 @@
 
         private VNode[] mNode = null;
         private String mId;
-        private int[] mCheckState = new int[MAX_STATES];
-        private boolean[] mCheckValue = new boolean[MAX_STATES];
-        private int mNumberOfStates = 0;
 
         public VPath() {
             // Empty constructor.
         }
 
-        public VPath(VPath p) {
-            copyFrom(p);
-        }
-
         public void toPath(Path path) {
             path.reset();
             if (mNode != null) {
@@ -663,18 +726,6 @@
                 mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
             }
 
-            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
-                mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
-            }
-
-            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
-                mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
-            }
-
-            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
-                mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
-            }
-
             if (themeAttrs == null
                     || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
                 mStrokeLineCap = getStrokeLineCap(
@@ -753,10 +804,6 @@
             mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
             mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
 
-            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
-            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
-            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
-
             mStrokeLineCap = getStrokeLineCap(a.getInt(
                     R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
             mStrokeLineJoin = getStrokeLineJoin(a.getInt(
@@ -775,6 +822,7 @@
                     R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
 
             updateColorAlphas();
+            a.recycle();
         }
 
         private void updateColorAlphas() {
@@ -877,33 +925,6 @@
             }
             return list.toArray(new VectorDrawable.VNode[list.size()]);
         }
-
-        public void copyFrom(VPath p1) {
-            mNode = new VNode[p1.mNode.length];
-            for (int i = 0; i < mNode.length; i++) {
-                mNode[i] = new VNode(p1.mNode[i]);
-            }
-            mId = p1.mId;
-            mStrokeColor = p1.mStrokeColor;
-            mFillColor = p1.mFillColor;
-            mStrokeWidth = p1.mStrokeWidth;
-            mRotate = p1.mRotate;
-            mPivotX = p1.mPivotX;
-            mPivotY = p1.mPivotY;
-            mTrimPathStart = p1.mTrimPathStart;
-            mTrimPathEnd = p1.mTrimPathEnd;
-            mTrimPathOffset = p1.mTrimPathOffset;
-            mStrokeLineCap = p1.mStrokeLineCap;
-            mStrokeLineJoin = p1.mStrokeLineJoin;
-            mStrokeMiterlimit = p1.mStrokeMiterlimit;
-            mNumberOfStates = p1.mNumberOfStates;
-            for (int i = 0; i < mNumberOfStates; i++) {
-                mCheckState[i] = p1.mCheckState[i];
-                mCheckValue[i] = p1.mCheckValue[i];
-            }
-
-            mFillRule = p1.mFillRule;
-        }
     }
 
     private static class VNode {
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index d4a23b8..8355f83 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -52,6 +52,7 @@
             : hasFunctors(false)
             , hasAnimations(false)
             , requiresUiRedraw(false)
+            , canDrawThisFrame(true)
         {}
         bool hasFunctors;
         // This is only updated if evaluateAnimations is true
@@ -60,6 +61,13 @@
         // animate itself, such as if hasFunctors is true
         // This is only set if hasAnimations is true
         bool requiresUiRedraw;
+        // This is set to true if draw() can be called this frame
+        // false means that we must delay until the next vsync pulse as frame
+        // production is outrunning consumption
+        // NOTE that if this is false CanvasContext will set either requiresUiRedraw
+        // *OR* will post itself for the next vsync automatically, use this
+        // only to avoid calling draw()
+        bool canDrawThisFrame;
     } out;
 
     // TODO: Damage calculations
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 839ef91..160fbea 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -360,7 +360,9 @@
     setSurface(NULL);
 }
 
-void CanvasContext::setSurface(EGLNativeWindowType window) {
+void CanvasContext::setSurface(ANativeWindow* window) {
+    mNativeWindow = window;
+
     if (mEglSurface != EGL_NO_SURFACE) {
         mGlobalContext->destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
@@ -393,7 +395,7 @@
     makeCurrent();
 }
 
-bool CanvasContext::initialize(EGLNativeWindowType window) {
+bool CanvasContext::initialize(ANativeWindow* window) {
     if (mCanvas) return false;
     setSurface(window);
     mCanvas = new OpenGLRenderer();
@@ -401,11 +403,11 @@
     return true;
 }
 
-void CanvasContext::updateSurface(EGLNativeWindowType window) {
+void CanvasContext::updateSurface(ANativeWindow* window) {
     setSurface(window);
 }
 
-void CanvasContext::pauseSurface(EGLNativeWindowType window) {
+void CanvasContext::pauseSurface(ANativeWindow* window) {
     // TODO: For now we just need a fence, in the future suspend any animations
     // and such to prevent from trying to render into this surface
 }
@@ -456,7 +458,15 @@
     info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
     mRootRenderNode->prepareTree(info);
 
-    if (info.out.hasAnimations) {
+    int runningBehind = 0;
+    // TODO: This query is moderately expensive, investigate adding some sort
+    // of fast-path based off when we last called eglSwapBuffers() as well as
+    // last vsync time. Or something.
+    mNativeWindow->query(mNativeWindow.get(),
+            NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
+    info.out.canDrawThisFrame = !runningBehind;
+
+    if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
         if (info.out.hasFunctors) {
             info.out.requiresUiRedraw = true;
         } else if (!info.out.requiresUiRedraw) {
@@ -467,6 +477,11 @@
     }
 }
 
+void CanvasContext::notifyFramePending() {
+    ATRACE_CALL();
+    mRenderThread.pushBackFrameCallback(this);
+}
+
 void CanvasContext::draw(Rect* dirty) {
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
             "drawDisplayList called on a context with no canvas or surface!");
@@ -515,7 +530,9 @@
     info.prepareTextures = false;
 
     prepareTree(info);
-    draw(NULL);
+    if (info.out.canDrawThisFrame) {
+        draw(NULL);
+    }
 }
 
 void CanvasContext::invokeFunctor(Functor* functor) {
@@ -539,6 +556,13 @@
     return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
 }
 
+void CanvasContext::flushCaches(Caches::FlushMode flushMode) {
+    if (mGlobalContext->hasContext()) {
+        requireGlContext();
+        Caches::getInstance().flush(flushMode);
+    }
+}
+
 void CanvasContext::runWithGlContext(RenderTask* task) {
     requireGlContext();
     task->run();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4232f27..da85d44 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -48,9 +48,9 @@
     CanvasContext(bool translucent, RenderNode* rootRenderNode);
     virtual ~CanvasContext();
 
-    bool initialize(EGLNativeWindowType window);
-    void updateSurface(EGLNativeWindowType window);
-    void pauseSurface(EGLNativeWindowType window);
+    bool initialize(ANativeWindow* window);
+    void updateSurface(ANativeWindow* window);
+    void pauseSurface(ANativeWindow* window);
     void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
     void setOpaque(bool opaque);
     void makeCurrent();
@@ -63,6 +63,8 @@
 
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
 
+    void flushCaches(Caches::FlushMode flushMode);
+
     void invokeFunctor(Functor* functor);
 
     void runWithGlContext(RenderTask* task);
@@ -73,11 +75,15 @@
     ANDROID_API static void setTextureAtlas(const sp<GraphicBuffer>& buffer,
             int64_t* map, size_t mapSize);
 
+    void notifyFramePending();
+
 private:
+    friend class RegisterFrameCallbackTask;
+
     void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
     void prepareTree(TreeInfo& info);
 
-    void setSurface(EGLNativeWindowType window);
+    void setSurface(ANativeWindow* window);
     void swapBuffers();
     void requireSurface();
 
@@ -85,6 +91,7 @@
 
     GlobalContext* mGlobalContext;
     RenderThread& mRenderThread;
+    sp<ANativeWindow> mNativeWindow;
     EGLSurface mEglSurface;
     bool mDirtyRegionsEnabled;
 
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 3b8786c..ee3e059 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -87,7 +87,13 @@
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
-    bool canUnblockUiThread = syncFrameState();
+    bool canUnblockUiThread;
+    bool canDrawThisFrame;
+    {
+        TreeInfo info;
+        canUnblockUiThread = syncFrameState(info);
+        canDrawThisFrame = info.out.canDrawThisFrame;
+    }
 
     // Grab a copy of everything we need
     Rect dirty(mDirty);
@@ -98,7 +104,9 @@
         unblockUiThread();
     }
 
-    context->draw(&dirty);
+    if (CC_LIKELY(canDrawThisFrame)) {
+        context->draw(&dirty);
+    }
 
     if (!canUnblockUiThread) {
         unblockUiThread();
@@ -111,12 +119,11 @@
     info.evaluateAnimations = true;
 }
 
-bool DrawFrameTask::syncFrameState() {
+bool DrawFrameTask::syncFrameState(TreeInfo& info) {
     ATRACE_CALL();
     mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
-    TreeInfo info;
     initTreeInfo(info);
     mContext->prepareDraw(&mLayers, info);
     if (info.out.hasAnimations) {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index b9307e1..acbc02a 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -24,6 +24,7 @@
 #include "RenderTask.h"
 
 #include "../Rect.h"
+#include "../TreeInfo.h"
 
 namespace android {
 namespace uirenderer {
@@ -65,7 +66,7 @@
 
 private:
     void postAndWait();
-    bool syncFrameState();
+    bool syncFrameState(TreeInfo& info);
     void unblockUiThread();
 
     Mutex mLock;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ef8e45b..8e772f2 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -112,7 +112,7 @@
     return (bool) postAndWait(task);
 }
 
-CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) {
+CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
     return (void*) args->context->initialize(args->window);
 }
 
@@ -123,7 +123,7 @@
     return (bool) postAndWait(task);
 }
 
-CREATE_BRIDGE2(updateSurface, CanvasContext* context, EGLNativeWindowType window) {
+CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
     args->context->updateSurface(args->window);
     return NULL;
 }
@@ -135,7 +135,7 @@
     postAndWait(task);
 }
 
-CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) {
+CREATE_BRIDGE2(pauseSurface, CanvasContext* context, ANativeWindow* window) {
     args->context->pauseSurface(args->window);
     return NULL;
 }
@@ -282,6 +282,18 @@
     post(task);
 }
 
+CREATE_BRIDGE2(flushCaches, CanvasContext* context, Caches::FlushMode flushMode) {
+    args->context->flushCaches(args->flushMode);
+    return NULL;
+}
+
+void RenderProxy::flushCaches(Caches::FlushMode flushMode) {
+    SETUP_TASK(flushCaches);
+    args->context = mContext;
+    args->flushMode = flushMode;
+    post(task);
+}
+
 CREATE_BRIDGE0(fence) {
     // Intentionally empty
     return NULL;
@@ -292,6 +304,17 @@
     postAndWait(task);
 }
 
+CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) {
+    args->context->notifyFramePending();
+    return NULL;
+}
+
+void RenderProxy::notifyFramePending() {
+    SETUP_TASK(notifyFramePending);
+    args->context = mContext;
+    mRenderThread.queueAtFront(task);
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 4d3499e..22d4e22 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -29,6 +29,7 @@
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
+#include "../Caches.h"
 #include "DrawFrameTask.h"
 
 namespace android {
@@ -81,7 +82,10 @@
     ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
     ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
 
+    ANDROID_API void flushCaches(Caches::FlushMode flushMode);
+
     ANDROID_API void fence();
+    ANDROID_API void notifyFramePending();
 
 private:
     RenderThread& mRenderThread;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 35a3eab..4a4e254 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -37,7 +37,7 @@
 static const size_t EVENT_BUFFER_SIZE = 100;
 
 // Slight delay to give the UI time to push us a new frame before we replay
-static const int DISPATCH_FRAME_CALLBACKS_DELAY = 0;
+static const int DISPATCH_FRAME_CALLBACKS_DELAY = 4;
 
 TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
 
@@ -91,6 +91,15 @@
     }
 }
 
+void TaskQueue::queueAtFront(RenderTask* task) {
+    if (mTail) {
+        task->mNext = mHead;
+        mHead = task;
+    } else {
+        mTail = mHead = task;
+    }
+}
+
 void TaskQueue::remove(RenderTask* task) {
     // TaskQueue is strict here to enforce that users are keeping track of
     // their RenderTasks due to how their memory is managed
@@ -188,20 +197,22 @@
     return latest;
 }
 
-void RenderThread::drainDisplayEventQueue() {
+void RenderThread::drainDisplayEventQueue(bool skipCallbacks) {
+    ATRACE_CALL();
     nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
     if (vsyncEvent > 0) {
         mVsyncRequested = false;
         mTimeLord.vsyncReceived(vsyncEvent);
-        if (!mFrameCallbackTaskPending) {
+        if (!skipCallbacks && !mFrameCallbackTaskPending) {
+            ATRACE_NAME("queue mFrameCallbackTask");
             mFrameCallbackTaskPending = true;
-            //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
-            queue(mFrameCallbackTask);
+            queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
         }
     }
 }
 
 void RenderThread::dispatchFrameCallbacks() {
+    ATRACE_CALL();
     mFrameCallbackTaskPending = false;
 
     std::set<IFrameCallback*> callbacks;
@@ -212,6 +223,15 @@
     }
 }
 
+void RenderThread::requestVsync() {
+    if (!mVsyncRequested) {
+        mVsyncRequested = true;
+        status_t status = mDisplayEventReceiver->requestNextVsync();
+        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
+                "requestNextVsync failed with status: %d", status);
+    }
+}
+
 bool RenderThread::threadLoop() {
     initializeDisplayEventReceiver();
 
@@ -236,6 +256,14 @@
                 timeoutMillis = 0;
             }
         }
+
+        if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
+            drainDisplayEventQueue(true);
+            mFrameCallbacks.insert(
+                    mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
+            mPendingRegistrationFrameCallbacks.clear();
+            requestVsync();
+        }
     }
 
     return false;
@@ -250,6 +278,12 @@
     }
 }
 
+void RenderThread::queueAtFront(RenderTask* task) {
+    AutoMutex _lock(mLock);
+    mQueue.queueAtFront(task);
+    mLooper->wake();
+}
+
 void RenderThread::queueDelayed(RenderTask* task, int delayMs) {
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     task->mRunAt = now + milliseconds_to_nanoseconds(delayMs);
@@ -262,17 +296,18 @@
 }
 
 void RenderThread::postFrameCallback(IFrameCallback* callback) {
-    mFrameCallbacks.insert(callback);
-    if (!mVsyncRequested) {
-        mVsyncRequested = true;
-        status_t status = mDisplayEventReceiver->requestNextVsync();
-        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                "requestNextVsync failed with status: %d", status);
-    }
+    mPendingRegistrationFrameCallbacks.insert(callback);
 }
 
 void RenderThread::removeFrameCallback(IFrameCallback* callback) {
     mFrameCallbacks.erase(callback);
+    mPendingRegistrationFrameCallbacks.erase(callback);
+}
+
+void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
+    if (mFrameCallbacks.erase(callback)) {
+        mPendingRegistrationFrameCallbacks.insert(callback);
+    }
 }
 
 RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
@@ -281,11 +316,13 @@
     if (!next) {
         mNextWakeup = LLONG_MAX;
     } else {
+        mNextWakeup = next->mRunAt;
         // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
         if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
             next = mQueue.next();
+        } else {
+            next = 0;
         }
-        mNextWakeup = next->mRunAt;
     }
     if (nextWakeup) {
         *nextWakeup = mNextWakeup;
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 215d294..4412584 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -44,6 +44,7 @@
 
     RenderTask* next();
     void queue(RenderTask* task);
+    void queueAtFront(RenderTask* task);
     RenderTask* peek();
     void remove(RenderTask* task);
 
@@ -66,12 +67,16 @@
     // RenderThread takes complete ownership of tasks that are queued
     // and will delete them after they are run
     ANDROID_API void queue(RenderTask* task);
+    ANDROID_API void queueAtFront(RenderTask* task);
     void queueDelayed(RenderTask* task, int delayMs);
     void remove(RenderTask* task);
 
     // Mimics android.view.Choreographer
     void postFrameCallback(IFrameCallback* callback);
     void removeFrameCallback(IFrameCallback* callback);
+    // If the callback is currently registered, it will be pushed back until
+    // the next vsync. If it is not currently registered this does nothing.
+    void pushBackFrameCallback(IFrameCallback* callback);
 
     TimeLord& timeLord() { return mTimeLord; }
 
@@ -87,8 +92,9 @@
 
     void initializeDisplayEventReceiver();
     static int displayEventReceiverCallback(int fd, int events, void* data);
-    void drainDisplayEventQueue();
+    void drainDisplayEventQueue(bool skipCallbacks = false);
     void dispatchFrameCallbacks();
+    void requestVsync();
 
     // Returns the next task to be run. If this returns NULL nextWakeup is set
     // to the time to requery for the nextTask to run. mNextWakeup is also
@@ -104,6 +110,11 @@
     DisplayEventReceiver* mDisplayEventReceiver;
     bool mVsyncRequested;
     std::set<IFrameCallback*> mFrameCallbacks;
+    // We defer the actual registration of these callbacks until
+    // both mQueue *and* mDisplayEventReceiver have been drained off all
+    // immediate events. This makes sure that we catch the next vsync, not
+    // the previous one
+    std::set<IFrameCallback*> mPendingRegistrationFrameCallbacks;
     bool mFrameCallbackTaskPending;
     DispatchFrameCallbacks* mFrameCallbackTask;
 
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
new file mode 100644
index 0000000..c088906
--- /dev/null
+++ b/media/java/android/media/AudioDevicePort.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+/**
+ * The AudioDevicePort is a specialized type of AudioPort
+ * describing an input (e.g microphone) or output device (e.g speaker)
+ * of the system.
+ * An AudioDevicePort is an AudioPort controlled by the audio HAL, almost always a physical
+ * device at the boundary of the audio system.
+ * In addition to base audio port attributes, the device descriptor contains:
+ * - the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
+ * - the device address (e.g MAC adddress for AD2P sink).
+ * @see AudioPort
+ * @hide
+ */
+
+public class AudioDevicePort extends AudioPort {
+
+    private final int mType;
+    private final String mAddress;
+
+    AudioDevicePort(AudioHandle handle, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains, int type, String address) {
+        super(handle,
+             (AudioManager.isInputDevice(type) == true)  ?
+                        AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
+             samplingRates, channelMasks, formats, gains);
+        mType = type;
+        mAddress = address;
+    }
+
+    /**
+     * Get the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
+     */
+    public int type() {
+        return mType;
+    }
+
+    /**
+     * Get the device address. Address format varies with the device type.
+     * - USB devices ({@link AudioManager#DEVICE_OUT_USB_DEVICE},
+     * {@link AudioManager#DEVICE_IN_USB_DEVICE}) use an address composed of the ALSA card number
+     * and device number: "card=2;device=1"
+     * - Bluetooth devices ({@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO},
+     * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP})
+     * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by
+     * {@link BluetoothDevice#getAddress()}.
+     * - Deivces that do not have an address will indicate an empty string "".
+     */
+    public String address() {
+        return mAddress;
+    }
+
+    /**
+     * Build a specific configuration of this audio device port for use by methods
+     * like AudioManager.connectAudioPatch().
+     */
+    public AudioDevicePortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                          AudioGainConfig gain) {
+        return new AudioDevicePortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioDevicePort)) {
+            return false;
+        }
+        return super.equals(o);
+    }
+}
diff --git a/media/java/android/media/AudioDevicePortConfig.java b/media/java/android/media/AudioDevicePortConfig.java
new file mode 100644
index 0000000..a381e10
--- /dev/null
+++ b/media/java/android/media/AudioDevicePortConfig.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+/**
+ * An AudioDevicePortConfig describes a possible configuration of an output or input device
+ * (speaker, headphone, microphone ...).
+ * It is used to specify a sink or source when creating a connection with
+ * AudioManager.connectAudioPatch().
+ * An AudioDevicePortConfig is obtained from AudioDevicePort.buildConfig().
+ * @hide
+ */
+
+public class AudioDevicePortConfig extends AudioPortConfig {
+    AudioDevicePortConfig(AudioDevicePort devicePort, int samplingRate, int channelMask,
+            int format, AudioGainConfig gain) {
+        super((AudioPort)devicePort, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Returns the audio device port this AudioDevicePortConfig is issued from.
+     */
+    public AudioDevicePort port() {
+        return (AudioDevicePort)mPort;
+    }
+}
+
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 57274ee..b07d2c5 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -156,4 +156,10 @@
         }
     }
 
+    /** @removed */
+    public AudioFormat()
+    {
+        throw new UnsupportedOperationException("There is no valid usage of this constructor");
+    }
+
 }
diff --git a/media/java/android/media/AudioGain.java b/media/java/android/media/AudioGain.java
new file mode 100644
index 0000000..57709d5
--- /dev/null
+++ b/media/java/android/media/AudioGain.java
@@ -0,0 +1,159 @@
+/*
+ * 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;
+
+/**
+ * The AudioGain describes a gain controller. Gain controllers are exposed by
+ * audio ports when the gain is configurable at this port's input or output.
+ * Gain values are expressed in millibels.
+ * A gain controller has the following attributes:
+ * - mode: defines modes of operation or features
+ *    MODE_JOINT: all channel gains are controlled simultaneously
+ *    MODE_CHANNELS: each channel gain is controlled individually
+ *    MODE_RAMP: ramps can be applied when gain changes
+ * - channel mask: indicates for which channels the gain can be controlled
+ * - min value: minimum gain value in millibel
+ * - max value: maximum gain value in millibel
+ * - default value: gain value after reset in millibel
+ * - step value: granularity of gain control in millibel
+ * - min ramp duration: minimum ramp duration in milliseconds
+ * - max ramp duration: maximum ramp duration in milliseconds
+ *
+ * This object is always created by the framework and read only by applications.
+ * Applications get a list of AudioGainDescriptors from AudioPortDescriptor.gains() and can build a
+ * valid gain configuration from AudioGain.buildConfig()
+ * @hide
+ */
+public class AudioGain {
+
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * all channel gains are controlled simultaneously
+     */
+    public static final int MODE_JOINT = 1;
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * each channel gain is controlled individually
+     */
+    public static final int MODE_CHANNELS = 2;
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * ramps can be applied when gain changes. The type of ramp (linear, log etc...) is
+     * implementation specific.
+     */
+    public static final int MODE_RAMP = 4;
+
+    private final int mIndex;
+    private final int mMode;
+    private final int mChannelMask;
+    private final int mMinValue;
+    private final int mMaxValue;
+    private final int mDefaultValue;
+    private final int mStepValue;
+    private final int mRampDurationMinMs;
+    private final int mRampDurationMaxMs;
+
+    // The channel mask passed to the constructor is as specified in AudioFormat
+    // (e.g. AudioFormat.CHANNEL_OUT_STEREO)
+    AudioGain(int index, int mode, int channelMask,
+                        int minValue, int maxValue, int defaultValue, int stepValue,
+                        int rampDurationMinMs, int rampDurationMaxMs) {
+        mIndex = index;
+        mMode = mode;
+        mChannelMask = channelMask;
+        mMinValue = minValue;
+        mMaxValue = maxValue;
+        mDefaultValue = defaultValue;
+        mStepValue = stepValue;
+        mRampDurationMinMs = rampDurationMinMs;
+        mRampDurationMaxMs = rampDurationMaxMs;
+    }
+
+    /**
+     * Bit field indicating supported modes of operation
+     */
+    public int mode() {
+        return mMode;
+    }
+
+    /**
+     * Indicates for which channels the gain can be controlled
+     * (e.g. AudioFormat.CHANNEL_OUT_STEREO)
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Minimum gain value in millibel
+     */
+    public int minValue() {
+        return mMinValue;
+    }
+
+    /**
+     * Maximum gain value in millibel
+     */
+    public int maxValue() {
+        return mMaxValue;
+    }
+
+    /**
+     * Default gain value in millibel
+     */
+    public int defaultValue() {
+        return mDefaultValue;
+    }
+
+    /**
+     * Granularity of gain control in millibel
+     */
+    public int stepValue() {
+        return mStepValue;
+    }
+
+    /**
+     * Minimum ramp duration in milliseconds
+     * 0 if MODE_RAMP not set
+     */
+    public int rampDurationMinMs() {
+        return mRampDurationMinMs;
+    }
+
+    /**
+     * Maximum ramp duration in milliseconds
+     * 0 if MODE_RAMP not set
+     */
+    public int rampDurationMaxMs() {
+        return mRampDurationMaxMs;
+    }
+
+    /**
+     * Build a valid gain configuration for this gain controller for use by
+     * AudioPortDescriptor.setGain()
+     * @param mode: desired mode of operation
+     * @param channelMask: channels of which the gain should be modified.
+     * @param values: gain values for each channels.
+     * @param rampDurationMs: ramp duration if mode MODE_RAMP is set.
+     * ignored if MODE_JOINT.
+     */
+    public AudioGainConfig buildConfig(int mode, int channelMask,
+                                       int[] values, int rampDurationMs) {
+        //TODO: check params here
+        return new AudioGainConfig(mIndex, this, mode, channelMask, values, rampDurationMs);
+    }
+}
diff --git a/media/java/android/media/AudioGainConfig.java b/media/java/android/media/AudioGainConfig.java
new file mode 100644
index 0000000..ea61679
--- /dev/null
+++ b/media/java/android/media/AudioGainConfig.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 android.media;
+
+/**
+ * The AudioGainConfig is used by APIs setting or getting values on a given gain
+ * controller. It contains a valid configuration (value, channels...) for a gain controller
+ * exposed by an audio port.
+ * @see AudioGain
+ * @see AudioPort
+ * @hide
+ */
+public class AudioGainConfig {
+    AudioGain mGain;
+    private final int mIndex;
+    private final int mMode;
+    private final int mChannelMask;
+    private final int mValues[];
+    private final int mRampDurationMs;
+
+    AudioGainConfig(int index, AudioGain gain, int mode, int channelMask,
+            int[] values, int rampDurationMs) {
+        mIndex = index;
+        mGain = gain;
+        mMode = mode;
+        mChannelMask = channelMask;
+        mValues = values;
+        mRampDurationMs = rampDurationMs;
+    }
+
+    /**
+     * get the index of the parent gain.
+     * frameworks use only.
+     */
+    int index() {
+        return mIndex;
+    }
+
+    /**
+     * Bit field indicating requested modes of operation. See {@link AudioGain#MODE_JOINT},
+     * {@link AudioGain#MODE_CHANNELS}, {@link AudioGain#MODE_RAMP}
+     */
+    public int mode() {
+        return mMode;
+    }
+
+    /**
+     * Indicates for which channels the gain is set.
+     * See {@link AudioFormat#CHANNEL_OUT_STEREO}, {@link AudioFormat#CHANNEL_OUT_MONO} ...
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Gain values for each channel in the order of bits set in
+     * channelMask() from LSB to MSB
+     */
+    public int[] values() {
+        return mValues;
+    }
+
+    /**
+     * Ramp duration in milliseconds. N/A if mode() does not
+     * specify MODE_RAMP.
+     */
+    public int rampDurationMs() {
+        return mRampDurationMs;
+    }
+}
diff --git a/media/java/android/media/AudioHandle.java b/media/java/android/media/AudioHandle.java
new file mode 100644
index 0000000..b58e7a3
--- /dev/null
+++ b/media/java/android/media/AudioHandle.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+/**
+ * The AudioHandle is used by the audio framework implementation to
+ * uniquely identify a particular component of the routing topology
+ * (AudioPort or AudioPatch)
+ * It is not visible or used at the API.
+ */
+class AudioHandle {
+    private final int mId;
+
+    AudioHandle(int id) {
+        mId = id;
+    }
+
+    int id() {
+        return mId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioHandle)) {
+            return false;
+        }
+        AudioHandle ah = (AudioHandle)o;
+        return mId == ah.id();
+    }
+
+    @Override
+    public int hashCode() {
+        return mId;
+    }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9803161..f4affa0 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -39,6 +39,7 @@
 import android.view.KeyEvent;
 
 import java.util.HashMap;
+import java.util.ArrayList;
 
 /**
  * AudioManager provides access to volume and ringer mode control.
@@ -2966,4 +2967,151 @@
             Log.w(TAG, "Error disabling safe media volume", e);
         }
     }
+
+    /**
+     * Return codes for listAudioPorts(), createAudioPatch() ...
+     */
+
+    /** @hide
+     */
+    public static final int SUCCESS = AudioSystem.SUCCESS;
+    /** @hide
+     */
+    public static final int ERROR = AudioSystem.ERROR;
+    /** @hide
+     */
+    public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
+    /** @hide
+     */
+    public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
+    /** @hide
+     */
+    public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
+    /** @hide
+     */
+    public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
+    /** @hide
+     */
+    public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
+
+    /**
+     * Returns a list of descriptors for all audio ports managed by the audio framework.
+     * Audio ports are nodes in the audio framework or audio hardware that can be configured
+     * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
+     * See AudioPort for a list of attributes of each audio port.
+     * @param ports An AudioPort ArrayList where the list will be returned.
+     * @hide
+     */
+    public int listAudioPorts(ArrayList<AudioPort> ports) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
+     * @see listAudioPorts(ArrayList<AudioPort>)
+     * @hide
+     */
+    public int listAudioDevicePorts(ArrayList<AudioPort> devices) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Create a connection between two or more devices. The framework will reject the request if
+     * device types are not compatible or the implementation does not support the requested
+     * configuration.
+     * NOTE: current implementation is limited to one source and one sink per patch.
+     * @param patch AudioPatch array where the newly created patch will be returned.
+     *              As input, if patch[0] is not null, the specified patch will be replaced by the
+     *              new patch created. This avoids calling releaseAudioPatch() when modifying a
+     *              patch and allows the implementation to optimize transitions.
+     * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
+     * @param sinks   List of sink audio ports. All must be AudioPort.ROLE_SINK.
+     *
+     * @return - {@link #SUCCESS} if connection is successful.
+     *         - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
+     *         - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
+     *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
+     *         a patch.
+     *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
+     *         - {@link #ERROR} if patch cannot be connected for any other reason.
+     *
+     *         patch[0] contains the newly created patch
+     * @hide
+     */
+    public int createAudioPatch(AudioPatch[] patch,
+                                 AudioPortConfig[] sources,
+                                 AudioPortConfig[] sinks) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Releases an existing audio patch connection.
+     * @param patch The audio patch to disconnect.
+     * @return - {@link #SUCCESS} if disconnection is successful.
+     *         - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
+     *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
+     *         a patch.
+     *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
+     *         - {@link #ERROR} if patch cannot be released for any other reason.
+     * @hide
+     */
+    public int releaseAudioPatch(AudioPatch patch) {
+        return  ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * List all existing connections between audio ports.
+     * @param patches An AudioPatch array where the list will be returned.
+     * @hide
+     */
+    public int listAudioPatches(ArrayList<AudioPatch> patches) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
+     * AudioGain.buildConfig()
+     * @hide
+     */
+    public int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Listener registered by client to be notified upon new audio port connections,
+     * disconnections or attributes update.
+     * @hide
+     */
+    public interface OnAudioPortUpdateListener {
+        /**
+         * Callback method called upon audio port list update.
+         * @param portList the updated list of audio ports
+         */
+        public void OnAudioPortListUpdate(AudioPort[] portList);
+
+        /**
+         * Callback method called upon audio patch list update.
+         * @param patchList the updated list of audio patches
+         */
+        public void OnAudioPatchListUpdate(AudioPatch[] patchList);
+
+        /**
+         * Callback method called when the mediaserver dies
+         */
+        public void OnServiceDied();
+    }
+
+    /**
+     * Register an audio port update listener.
+     * @hide
+     */
+    public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
+    }
+
+    /**
+     * Unregister an audio port update listener.
+     * @hide
+     */
+    public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
+    }
 }
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
new file mode 100644
index 0000000..1500a43
--- /dev/null
+++ b/media/java/android/media/AudioMixPort.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+/**
+ * The AudioMixPort is a specialized type of AudioPort
+ * describing an audio mix or stream at an input or output stream of the audio
+ * framework.
+ * @see AudioPort
+ * @hide
+ */
+
+public class AudioMixPort extends AudioPort {
+
+    AudioMixPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains) {
+        super(handle, role, samplingRates, channelMasks, formats, gains);
+    }
+
+    /**
+     * Build a specific configuration of this audio mix port for use by methods
+     * like AudioManager.connectAudioPatch().
+     */
+    public AudioMixPortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                       AudioGainConfig gain) {
+        return new AudioMixPortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioMixPort)) {
+            return false;
+        }
+        return super.equals(o);
+    }
+
+}
diff --git a/media/java/android/media/AudioMixPortConfig.java b/media/java/android/media/AudioMixPortConfig.java
new file mode 100644
index 0000000..8eb9ef46
--- /dev/null
+++ b/media/java/android/media/AudioMixPortConfig.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+/**
+ * An AudioMixPortConfig describes a possible configuration of an output or input mixer.
+ * It is used to specify a sink or source when creating a connection with
+ * AudioManager.connectAudioPatch().
+ * An AudioMixPortConfig is obtained from AudioMixPort.buildConfig().
+ * @hide
+ */
+
+public class AudioMixPortConfig extends AudioPortConfig {
+
+    AudioMixPortConfig(AudioMixPort mixPort, int samplingRate, int channelMask, int format,
+                AudioGainConfig gain) {
+        super((AudioPort)mixPort, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Returns the audio mix port this AudioMixPortConfig is issued from.
+     */
+    public AudioMixPort port() {
+        return (AudioMixPort)mPort;
+    }
+}
+
diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java
new file mode 100644
index 0000000..72291f6
--- /dev/null
+++ b/media/java/android/media/AudioPatch.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+
+/**
+ * An AudioPatch describes a connection between audio sources and audio sinks.
+ * An audio source can be an output mix (playback AudioBus) or an input device (microphone).
+ * An audio sink can be an output device (speaker) or an input mix (capture AudioBus).
+ * An AudioPatch is created by AudioManager.connectAudioPatch() and released by
+ * AudioManager.disconnectAudioPatch()
+ * It contains the list of source and sink AudioPortConfig showing audio port configurations
+ * being connected.
+ * @hide
+ */
+public class AudioPatch {
+
+    private final AudioHandle mHandle;
+    private final AudioPortConfig[] mSources;
+    private final AudioPortConfig[] mSinks;
+
+    AudioPatch(AudioHandle patchHandle, AudioPortConfig[] sources, AudioPortConfig[] sinks) {
+        mHandle = patchHandle;
+        mSources = sources;
+        mSinks = sinks;
+    }
+
+    /**
+     * Retrieve the list of sources of this audio patch.
+     */
+    public AudioPortConfig[] sources() {
+        return mSources;
+    }
+
+    /**
+     * Retreive the list of sinks of this audio patch.
+     */
+    public AudioPortConfig[] sinks() {
+        return mSinks;
+    }
+}
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
new file mode 100644
index 0000000..9aeddef
--- /dev/null
+++ b/media/java/android/media/AudioPort.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+
+/**
+ * An audio port is a node of the audio framework or hardware that can be connected to or
+ * disconnect from another audio node to create a specific audio routing configuration.
+ * Examples of audio ports are an output device (speaker) or an output mix (see AudioMixPort).
+ * All attributes that are relevant for applications to make routing selection are decribed
+ * in an AudioPort,  in particular:
+ * - possible channel mask configurations.
+ * - audio format (PCM 16bit, PCM 24bit...)
+ * - gain: a port can be associated with one or more gain controllers (see AudioGain).
+ *
+ * This object is always created by the framework and read only by applications.
+ * A list of all audio port descriptors currently available for applications to control
+ * is obtained by AudioManager.listAudioPorts().
+ * An application can obtain an AudioPortConfig for a valid configuration of this port
+ * by calling AudioPort.buildConfig() and use this configuration
+ * to create a connection between audio sinks and sources with AudioManager.connectAudioPatch()
+ *
+ * @hide
+ */
+public class AudioPort {
+
+    /**
+     * For use by the audio framework.
+     */
+    public static final int ROLE_NONE = 0;
+    /**
+     * The audio port is a source (produces audio)
+     */
+    public static final int ROLE_SOURCE = 1;
+    /**
+     * The audio port is a sink (consumes audio)
+     */
+    public static final int ROLE_SINK = 2;
+
+    /**
+     * audio port type for use by audio framework implementation
+     */
+    public static final int TYPE_NONE = 0;
+    /**
+     */
+    public static final int TYPE_DEVICE = 1;
+    /**
+     */
+    public static final int TYPE_SUBMIX = 2;
+    /**
+     */
+    public static final int TYPE_SESSION = 3;
+
+
+    AudioHandle mHandle;
+    private final int mRole;
+    private final int[] mSamplingRates;
+    private final int[] mChannelMasks;
+    private final int[] mFormats;
+    private final AudioGain[] mGains;
+    private AudioPortConfig mActiveConfig;
+
+    AudioPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains) {
+        mHandle = handle;
+        mRole = role;
+        mSamplingRates = samplingRates;
+        mChannelMasks = channelMasks;
+        mFormats = formats;
+        mGains = gains;
+    }
+
+    AudioHandle handle() {
+        return mHandle;
+    }
+
+    /**
+     * Get the audio port role
+     */
+    public int role() {
+        return mRole;
+    }
+
+    /**
+     * Get the list of supported sampling rates
+     * Empty array if sampling rate is not relevant for this audio port
+     */
+    public int[] samplingRates() {
+        return mSamplingRates;
+    }
+
+    /**
+     * Get the list of supported channel mask configurations
+     * (e.g AudioFormat.CHANNEL_OUT_STEREO)
+     * Empty array if channel mask is not relevant for this audio port
+     */
+    public int[] channelMasks() {
+        return mChannelMasks;
+    }
+
+    /**
+     * Get the list of supported audio format configurations
+     * (e.g AudioFormat.ENCODING_PCM_16BIT)
+     * Empty array if format is not relevant for this audio port
+     */
+    public int[] formats() {
+        return mFormats;
+    }
+
+    /**
+     * Get the list of gain descriptors
+     * Empty array if this port does not have gain control
+     */
+    public AudioGain[] gains() {
+        return mGains;
+    }
+
+    /**
+     * Get the gain descriptor at a given index
+     */
+    AudioGain gain(int index) {
+        return mGains[index];
+    }
+
+    /**
+     * Build a specific configuration of this audio port for use by methods
+     * like AudioManager.connectAudioPatch().
+     * @param channelMask The desired channel mask. AudioFormat.CHANNEL_OUT_DEFAULT if no change
+     * from active configuration requested.
+     * @param format The desired audio format. AudioFormat.ENCODING_DEFAULT if no change
+     * from active configuration requested.
+     * @param gain The desired gain. null if no gain changed requested.
+     */
+    public AudioPortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                        AudioGainConfig gain) {
+        return new AudioPortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Get currently active configuration of this audio port.
+     */
+    public AudioPortConfig activeConfig() {
+        return mActiveConfig;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioPort)) {
+            return false;
+        }
+        AudioPort ap = (AudioPort)o;
+        return mHandle.equals(ap.handle());
+    }
+
+    @Override
+    public int hashCode() {
+        return mHandle.hashCode();
+    }
+}
+
diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java
new file mode 100644
index 0000000..5dc768d
--- /dev/null
+++ b/media/java/android/media/AudioPortConfig.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+/**
+ * An AudioPortConfig contains a possible configuration of an audio port chosen
+ * among all possible attributes described by an AudioPort.
+ * An AudioPortConfig is created by AudioPort.buildConfiguration().
+ * AudioPorts are used to specify the sources and sinks of a patch created
+ * with AudioManager.connectAudioPatch().
+ * Several specialized versions of AudioPortConfig exist to handle different categories of
+ * audio ports and their specific attributes:
+ * - AudioDevicePortConfig for input (e.g micropohone) and output devices (e.g speaker)
+ * - AudioMixPortConfig for input or output streams of the audio framework.
+ * @hide
+ */
+
+public class AudioPortConfig {
+    final AudioPort mPort;
+    private final int mSamplingRate;
+    private final int mChannelMask;
+    private final int mFormat;
+    private final AudioGainConfig mGain;
+
+    // mConfigMask indicates which fields in this configuration should be
+    // taken into account. Used with AudioSystem.setAudioPortConfig()
+    // framework use only.
+    static final int SAMPLE_RATE  = 0x1;
+    static final int CHANNEL_MASK = 0x2;
+    static final int FORMAT       = 0x4;
+    static final int GAIN         = 0x8;
+    int mConfigMask;
+
+    AudioPortConfig(AudioPort port, int samplingRate, int channelMask, int format,
+            AudioGainConfig gain) {
+        mPort = port;
+        mSamplingRate = samplingRate;
+        mChannelMask = channelMask;
+        mFormat = format;
+        mGain = gain;
+        mConfigMask = 0;
+    }
+
+    /**
+     * Returns the audio port this AudioPortConfig is issued from.
+     */
+    public AudioPort port() {
+        return mPort;
+    }
+
+    /**
+     * Sampling rate configured for this AudioPortConfig.
+     */
+    public int samplingRate() {
+        return mSamplingRate;
+    }
+
+    /**
+     * Channel mask configuration (e.g AudioFormat.CHANNEL_CONFIGURATION_STEREO).
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Audio format configuration (e.g AudioFormat.ENCODING_PCM_16BIT).
+     */
+    public int format() {
+        return mFormat;
+    }
+
+    /**
+     * The gain configuration if this port supports gain control, null otherwise
+     * @see AudioGainConfig.
+     */
+    public AudioGainConfig gain() {
+        return mGain;
+    }
+}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index c736fc7..cf18902 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,6 +112,9 @@
     private static final boolean USE_SESSIONS = true;
     private static final boolean DEBUG_SESSIONS = true;
 
+    /** Allow volume changes to set ringer mode to silent? */
+    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
+
     /** How long to delay before persisting a change in volume/ringer mode. */
     private static final int PERSIST_DELAY = 500;
 
@@ -1019,7 +1022,8 @@
             int newRingerMode;
             if (index == 0) {
                 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
-                                              : AudioManager.RINGER_MODE_SILENT;
+                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
+                        : AudioManager.RINGER_MODE_NORMAL;
             } else {
                 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
             }
@@ -2552,7 +2556,9 @@
                     }
                 } else {
                     // (oldIndex < step) is equivalent to (old UI index == 0)
-                    if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                    if ((oldIndex < step)
+                            && VOLUME_SETS_RINGER_MODE_SILENT
+                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                         ringerMode = RINGER_MODE_SILENT;
                     }
                 }
@@ -2565,7 +2571,8 @@
                 break;
             }
             if ((direction == AudioManager.ADJUST_LOWER)) {
-                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                if (VOLUME_SETS_RINGER_MODE_SILENT
+                        && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                     ringerMode = RINGER_MODE_SILENT;
                 }
             } else if (direction == AudioManager.ADJUST_RAISE) {
@@ -2909,54 +2916,56 @@
             return name + "_" + suffix;
         }
 
-        public synchronized void readSettings() {
-            // force maximum volume on all streams if fixed volume property is set
-            if (mUseFixedVolume) {
-                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
-                return;
-            }
-            // do not read system stream volume from settings: this stream is always aliased
-            // to another stream type and its volume is never persisted. Values in settings can
-            // only be stale values
-            if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
-                    (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
-                int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
-                synchronized (mCameraSoundForced) {
-                    if (mCameraSoundForced) {
-                        index = mIndexMax;
+        public void readSettings() {
+            synchronized (VolumeStreamState.class) {
+                // force maximum volume on all streams if fixed volume property is set
+                if (mUseFixedVolume) {
+                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
+                    return;
+                }
+                // do not read system stream volume from settings: this stream is always aliased
+                // to another stream type and its volume is never persisted. Values in settings can
+                // only be stale values
+                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
+                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
+                    int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
+                    synchronized (mCameraSoundForced) {
+                        if (mCameraSoundForced) {
+                            index = mIndexMax;
+                        }
                     }
-                }
-                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
-                return;
-            }
-
-            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
-
-            for (int i = 0; remainingDevices != 0; i++) {
-                int device = (1 << i);
-                if ((device & remainingDevices) == 0) {
-                    continue;
-                }
-                remainingDevices &= ~device;
-
-                // retrieve current volume for device
-                String name = getSettingNameForDevice(device);
-                // if no volume stored for current stream and device, use default volume if default
-                // device, continue otherwise
-                int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
-                                        AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
-                int index = Settings.System.getIntForUser(
-                        mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
-                if (index == -1) {
-                    continue;
+                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
+                    return;
                 }
 
-                // 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));
+                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
+
+                for (int i = 0; remainingDevices != 0; i++) {
+                    int device = (1 << i);
+                    if ((device & remainingDevices) == 0) {
+                        continue;
+                    }
+                    remainingDevices &= ~device;
+
+                    // retrieve current volume for device
+                    String name = getSettingNameForDevice(device);
+                    // if no volume stored for current stream and device, use default volume if default
+                    // device, continue otherwise
+                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
+                                            AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
+                    int index = Settings.System.getIntForUser(
+                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
+                    if (index == -1) {
+                        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));
+                    }
                 }
             }
         }
@@ -2974,32 +2983,34 @@
             AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
         }
 
-        public synchronized void applyAllVolumes() {
-            // apply default volume first: by convention this will reset all
-            // devices volumes in audio policy manager to the supplied value
-            int index;
-            if (isMuted()) {
-                index = 0;
-            } else {
-                index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
-            }
-            AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
-            // then apply device specific volumes
-            Set set = mIndex.entrySet();
-            Iterator i = set.iterator();
-            while (i.hasNext()) {
-                Map.Entry entry = (Map.Entry)i.next();
-                int device = ((Integer)entry.getKey()).intValue();
-                if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
-                    if (isMuted()) {
-                        index = 0;
-                    } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
-                            mAvrcpAbsVolSupported) {
-                        index = (mIndexMax + 5)/10;
-                    } else {
-                        index = ((Integer)entry.getValue() + 5)/10;
+        public void applyAllVolumes() {
+            synchronized (VolumeStreamState.class) {
+                // apply default volume first: by convention this will reset all
+                // devices volumes in audio policy manager to the supplied value
+                int index;
+                if (isMuted()) {
+                    index = 0;
+                } else {
+                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
+                }
+                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
+                // then apply device specific volumes
+                Set set = mIndex.entrySet();
+                Iterator i = set.iterator();
+                while (i.hasNext()) {
+                    Map.Entry entry = (Map.Entry)i.next();
+                    int device = ((Integer)entry.getKey()).intValue();
+                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
+                        if (isMuted()) {
+                            index = 0;
+                        } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                                mAvrcpAbsVolSupported) {
+                            index = (mIndexMax + 5)/10;
+                        } else {
+                            index = ((Integer)entry.getValue() + 5)/10;
+                        }
+                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
                     }
-                    AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
                 }
             }
         }
@@ -3009,94 +3020,104 @@
                             device);
         }
 
-        public synchronized boolean setIndex(int index, int device) {
-            int oldIndex = getIndex(device);
-            index = getValidIndex(index);
-            synchronized (mCameraSoundForced) {
-                if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
-                    index = mIndexMax;
-                }
-            }
-            mIndex.put(device, index);
-
-            if (oldIndex != index) {
-                // Apply change to all streams using this one as alias
-                // if changing volume of current device, also change volume of current
-                // device on aliased stream
-                boolean currentDevice = (device == getDeviceForStream(mStreamType));
-                int numStreamTypes = AudioSystem.getNumStreamTypes();
-                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                    if (streamType != mStreamType &&
-                            mStreamVolumeAlias[streamType] == mStreamType) {
-                        int scaledIndex = rescaleIndex(index, mStreamType, streamType);
-                        mStreamStates[streamType].setIndex(scaledIndex,
-                                                           device);
-                        if (currentDevice) {
-                            mStreamStates[streamType].setIndex(scaledIndex,
-                                                               getDeviceForStream(streamType));
-                        }
+        public boolean setIndex(int index, int device) {
+            synchronized (VolumeStreamState.class) {
+                int oldIndex = getIndex(device);
+                index = getValidIndex(index);
+                synchronized (mCameraSoundForced) {
+                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
+                        index = mIndexMax;
                     }
                 }
-                return true;
-            } else {
-                return false;
+                mIndex.put(device, index);
+
+                if (oldIndex != index) {
+                    // Apply change to all streams using this one as alias
+                    // if changing volume of current device, also change volume of current
+                    // device on aliased stream
+                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
+                    int numStreamTypes = AudioSystem.getNumStreamTypes();
+                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                        if (streamType != mStreamType &&
+                                mStreamVolumeAlias[streamType] == mStreamType) {
+                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
+                            mStreamStates[streamType].setIndex(scaledIndex,
+                                                               device);
+                            if (currentDevice) {
+                                mStreamStates[streamType].setIndex(scaledIndex,
+                                                                   getDeviceForStream(streamType));
+                            }
+                        }
+                    }
+                    return true;
+                } else {
+                    return false;
+                }
             }
         }
 
-        public synchronized int getIndex(int device) {
-            Integer index = mIndex.get(device);
-            if (index == null) {
-                // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
-                index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
+        public int getIndex(int device) {
+            synchronized (VolumeStreamState.class) {
+                Integer index = mIndex.get(device);
+                if (index == null) {
+                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
+                    index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
+                }
+                return index.intValue();
             }
-            return index.intValue();
         }
 
         public int getMaxIndex() {
             return mIndexMax;
         }
 
-        public synchronized void setAllIndexes(VolumeStreamState srcStream) {
-            int srcStreamType = srcStream.getStreamType();
-            // apply default device volume from source stream to all devices first in case
-            // some devices are present in this stream state but not in source stream state
-            int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
-            index = rescaleIndex(index, srcStreamType, mStreamType);
-            Set set = mIndex.entrySet();
-            Iterator i = set.iterator();
-            while (i.hasNext()) {
-                Map.Entry entry = (Map.Entry)i.next();
-                entry.setValue(index);
-            }
-            // Now apply actual volume for devices in source stream state
-            set = srcStream.mIndex.entrySet();
-            i = set.iterator();
-            while (i.hasNext()) {
-                Map.Entry entry = (Map.Entry)i.next();
-                int device = ((Integer)entry.getKey()).intValue();
-                index = ((Integer)entry.getValue()).intValue();
+        public void setAllIndexes(VolumeStreamState srcStream) {
+            synchronized (VolumeStreamState.class) {
+                int srcStreamType = srcStream.getStreamType();
+                // apply default device volume from source stream to all devices first in case
+                // some devices are present in this stream state but not in source stream state
+                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
                 index = rescaleIndex(index, srcStreamType, mStreamType);
+                Set set = mIndex.entrySet();
+                Iterator i = set.iterator();
+                while (i.hasNext()) {
+                    Map.Entry entry = (Map.Entry)i.next();
+                    entry.setValue(index);
+                }
+                // Now apply actual volume for devices in source stream state
+                set = srcStream.mIndex.entrySet();
+                i = set.iterator();
+                while (i.hasNext()) {
+                    Map.Entry entry = (Map.Entry)i.next();
+                    int device = ((Integer)entry.getKey()).intValue();
+                    index = ((Integer)entry.getValue()).intValue();
+                    index = rescaleIndex(index, srcStreamType, mStreamType);
 
-                setIndex(index, device);
+                    setIndex(index, device);
+                }
             }
         }
 
-        public synchronized void setAllIndexesToMax() {
-            Set set = mIndex.entrySet();
-            Iterator i = set.iterator();
-            while (i.hasNext()) {
-                Map.Entry entry = (Map.Entry)i.next();
-                entry.setValue(mIndexMax);
+        public void setAllIndexesToMax() {
+            synchronized (VolumeStreamState.class) {
+                Set set = mIndex.entrySet();
+                Iterator i = set.iterator();
+                while (i.hasNext()) {
+                    Map.Entry entry = (Map.Entry)i.next();
+                    entry.setValue(mIndexMax);
+                }
             }
         }
 
-        public synchronized void mute(IBinder cb, boolean state) {
-            VolumeDeathHandler handler = getDeathHandler(cb, state);
-            if (handler == null) {
-                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
-                return;
+        public void mute(IBinder cb, boolean state) {
+            synchronized (VolumeStreamState.class) {
+                VolumeDeathHandler handler = getDeathHandler(cb, state);
+                if (handler == null) {
+                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
+                    return;
+                }
+                handler.mute(state);
             }
-            handler.mute(state);
         }
 
         public int getStreamType() {
diff --git a/media/java/android/media/DngCreator.java b/media/java/android/media/DngCreator.java
deleted file mode 100644
index 76c6d46..0000000
--- a/media/java/android/media/DngCreator.java
+++ /dev/null
@@ -1,368 +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;
-
-import android.graphics.Bitmap;
-import android.graphics.ImageFormat;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.location.Location;
-import android.util.Size;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-
-/**
- * The {@link DngCreator} class provides functions to write raw pixel data as a DNG file.
- *
- * <p>
- * This class is designed to be used with the {@link android.graphics.ImageFormat#RAW_SENSOR}
- * buffers available from {@link android.hardware.camera2.CameraDevice}, or with Bayer-type raw
- * pixel data that is otherwise generated by an application.  The DNG metadata tags will be
- * generated from a {@link android.hardware.camera2.CaptureResult} object or set directly.
- * </p>
- *
- * <p>
- * The DNG file format is a cross-platform file format that is used to store pixel data from
- * camera sensors with minimal pre-processing applied.  DNG files allow for pixel data to be
- * defined in a user-defined colorspace, and have associated metadata that allow for this
- * pixel data to be converted to the standard CIE XYZ colorspace during post-processing.
- * </p>
- *
- * <p>
- * For more information on the DNG file format and associated metadata, please refer to the
- * <a href=
- * "https://wwwimages2.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf">
- * Adobe DNG 1.4.0.0 specification</a>.
- * </p>
- */
-public final class DngCreator implements AutoCloseable {
-
-    /**
-     * Create a new DNG object.
-     *
-     * <p>
-     * It is not necessary to call any set methods to write a well-formatted DNG file.
-     * </p>
-     * <p>
-     * DNG metadata tags will be generated from the corresponding parameters in the
-     * {@link android.hardware.camera2.CaptureResult} object.  This removes or overrides
-     * all previous tags set.
-     * </p>
-     *
-     * @param characteristics an object containing the static
-     *          {@link android.hardware.camera2.CameraCharacteristics}.
-     * @param metadata a metadata object to generate tags from.
-     */
-    public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {
-        if (characteristics == null || metadata == null) {
-            throw new NullPointerException("Null argument to DngCreator constructor");
-        }
-        nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy());
-    }
-
-    /**
-     * Set the orientation value to write.
-     *
-     * <p>
-     * This will be written as the TIFF "Orientation" tag {@code (0x0112)}.
-     * Calling this will override any prior settings for this tag.
-     * </p>
-     *
-     * @param orientation the orientation value to set, one of:
-     *                    <ul>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_NORMAL}</li>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_HORIZONTAL}</li>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_180}</li>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_VERTICAL}</li>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_TRANSPOSE}</li>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_90}</li>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_TRANSVERSE}</li>
-     *                      <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_270}</li>
-     *                    </ul>
-     * @return this {@link #DngCreator} object.
-     */
-    public DngCreator setOrientation(int orientation) {
-
-        if (orientation < ExifInterface.ORIENTATION_UNDEFINED ||
-                orientation > ExifInterface.ORIENTATION_ROTATE_270) {
-            throw new IllegalArgumentException("Orientation " + orientation +
-                    " is not a valid EXIF orientation value");
-        }
-        nativeSetOrientation(orientation);
-        return this;
-    }
-
-    /**
-     * Set the thumbnail image.
-     *
-     * <p>
-     * Pixel data will be converted to a Baseline TIFF RGB image, with 8 bits per color channel.
-     * The alpha channel will be discarded.
-     * </p>
-     *
-     * <p>
-     * The given bitmap should not be altered while this object is in use.
-     * </p>
-     *
-     * @param pixels a {@link android.graphics.Bitmap} of pixel data.
-     * @return this {@link #DngCreator} object.
-     */
-    public DngCreator setThumbnail(Bitmap pixels) {
-        if (pixels == null) {
-            throw new NullPointerException("Null argument to setThumbnail");
-        }
-
-        Bitmap.Config config = pixels.getConfig();
-
-        if (config != Bitmap.Config.ARGB_8888) {
-            pixels = pixels.copy(Bitmap.Config.ARGB_8888, false);
-            if (pixels == null) {
-                throw new IllegalArgumentException("Unsupported Bitmap format " + config);
-            }
-            nativeSetThumbnailBitmap(pixels);
-        }
-
-        return this;
-    }
-
-    /**
-     * Set the thumbnail image.
-     *
-     * <p>
-     * Pixel data is interpreted as a {@link android.graphics.ImageFormat#YUV_420_888} image.
-     * </p>
-     *
-     * <p>
-     * The given image should not be altered while this object is in use.
-     * </p>
-     *
-     * @param pixels an {@link android.media.Image} object with the format
-     *               {@link android.graphics.ImageFormat#YUV_420_888}.
-     * @return this {@link #DngCreator} object.
-     */
-    public DngCreator setThumbnail(Image pixels) {
-        if (pixels == null) {
-            throw new NullPointerException("Null argument to setThumbnail");
-        }
-
-        int format = pixels.getFormat();
-        if (format != ImageFormat.YUV_420_888) {
-            throw new IllegalArgumentException("Unsupported image format " + format);
-        }
-
-        Image.Plane[] planes = pixels.getPlanes();
-        nativeSetThumbnailImage(pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
-                planes[0].getRowStride(), planes[0].getPixelStride(), planes[1].getBuffer(),
-                planes[1].getRowStride(), planes[1].getPixelStride(), planes[1].getBuffer(),
-                planes[1].getRowStride(), planes[1].getPixelStride());
-
-        return this;
-    }
-
-
-    /**
-     * Set image location metadata.
-     *
-     * <p>
-     * The given location object must contain at least a valid time, latitude, and longitude
-     * (equivalent to the values returned by {@link android.location.Location#getTime()},
-     * {@link android.location.Location#getLatitude()}, and
-     * {@link android.location.Location#getLongitude()} methods).
-     * </p>
-     *
-     * @param location an {@link android.location.Location} object to set.
-     * @return this {@link #DngCreator} object.
-     *
-     * @throws java.lang.IllegalArgumentException if the given location object doesn't
-     *          contain enough information to set location metadata.
-     */
-    public DngCreator setLocation(Location location) {
-        /*TODO*/
-        return this;
-    }
-
-    /**
-     * Set the user description string to write.
-     *
-     * <p>
-     * This is equivalent to setting the TIFF "ImageDescription" tag {@code (0x010E)}.
-     * </p>
-     *
-     * @param description the user description string.
-     * @return this {@link #DngCreator} object.
-     */
-    public DngCreator setDescription(String description) {
-        /*TODO*/
-        return this;
-    }
-
-    /**
-     * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
-     * the currently configured metadata.
-     *
-     * <p>
-     * Raw pixel data must have 16 bits per pixel, and the input must contain at least
-     * {@code offset + 2 * width * height)} bytes.  The width and height of
-     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
-     * and will typically be equal to the width and height of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
-     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
-     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
-     * metadata is available to write a well-formatted DNG file, an
-     * {@link java.lang.IllegalStateException} will be thrown.
-     * </p>
-     *
-     * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
-     * @param size the {@link Size} of the image to write, in pixels.
-     * @param pixels an {@link java.io.InputStream} of pixel data to write.
-     * @param offset the offset of the raw image in bytes.  This indicates how many bytes will
-     *               be skipped in the input before any pixel data is read.
-     *
-     * @throws IOException if an error was encountered in the input or output stream.
-     * @throws java.lang.IllegalStateException if not enough metadata information has been
-     *          set to write a well-formatted DNG file.
-     * @throws java.lang.IllegalArgumentException if the size passed in does not match the
-     */
-    public void writeInputStream(OutputStream dngOutput, Size size, InputStream pixels, long offset)
-            throws IOException {
-        if (dngOutput == null || pixels == null) {
-            throw new NullPointerException("Null argument to writeImage");
-        }
-        nativeWriteInputStream(dngOutput, pixels, offset);
-    }
-
-    /**
-     * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
-     * the currently configured metadata.
-     *
-     * <p>
-     * Raw pixel data must have 16 bits per pixel, and the input must contain at least
-     * {@code offset + 2 * width * height)} bytes.  The width and height of
-     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
-     * and will typically be equal to the width and height of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
-     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
-     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
-     * metadata is available to write a well-formatted DNG file, an
-     * {@link java.lang.IllegalStateException} will be thrown.
-     * </p>
-     *
-     * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
-     * @param pixels an {@link java.nio.ByteBuffer} of pixel data to write.
-     * @param offset the offset of the raw image in bytes.  This indicates how many bytes will
-     *               be skipped in the input before any pixel data is read.
-     *
-     * @throws IOException if an error was encountered in the input or output stream.
-     * @throws java.lang.IllegalStateException if not enough metadata information has been
-     *          set to write a well-formatted DNG file.
-     */
-    public void writeByteBuffer(OutputStream dngOutput, Size size, ByteBuffer pixels, long offset)
-            throws IOException {
-        if (dngOutput == null || pixels == null) {
-            throw new NullPointerException("Null argument to writeImage");
-        }
-        nativeWriteByteBuffer(dngOutput, pixels, offset);
-    }
-
-    /**
-     * Write the pixel data to a DNG file with the currently configured metadata.
-     *
-     * <p>
-     * For this method to succeed, the {@link android.media.Image} input must contain
-     * {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data, otherwise an
-     * {@link java.lang.IllegalArgumentException} will be thrown.
-     * </p>
-     *
-     * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
-     * @param pixels an {@link android.media.Image} to write.
-     *
-     * @throws java.io.IOException if an error was encountered in the output stream.
-     * @throws java.lang.IllegalArgumentException if an image with an unsupported format was used.
-     * @throws java.lang.IllegalStateException if not enough metadata information has been
-     *          set to write a well-formatted DNG file.
-     */
-    public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {
-        if (dngOutput == null || pixels == null) {
-            throw new NullPointerException("Null argument to writeImage");
-        }
-
-        int format = pixels.getFormat();
-        if (format != ImageFormat.RAW_SENSOR) {
-            throw new IllegalArgumentException("Unsupported image format " + format);
-        }
-
-        Image.Plane[] planes = pixels.getPlanes();
-        nativeWriteImage(dngOutput, pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
-                planes[0].getRowStride(), planes[0].getPixelStride());
-    }
-
-    @Override
-    public void close() {
-        nativeDestroy();
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            close();
-        } finally {
-            super.finalize();
-        }
-    }
-
-    /**
-     * This field is used by native code, do not access or modify.
-     */
-    private long mNativeContext;
-
-    private static native void nativeClassInit();
-
-    private synchronized native void nativeInit(CameraMetadataNative nativeCharacteristics,
-                                                CameraMetadataNative nativeResult);
-
-    private synchronized native void nativeDestroy();
-
-    private synchronized native void nativeSetOrientation(int orientation);
-
-    private synchronized native void nativeSetThumbnailBitmap(Bitmap bitmap);
-
-    private synchronized native void nativeSetThumbnailImage(int width, int height,
-                                                             ByteBuffer yBuffer, int yRowStride,
-                                                             int yPixStride, ByteBuffer uBuffer,
-                                                             int uRowStride, int uPixStride,
-                                                             ByteBuffer vBuffer, int vRowStride,
-                                                             int vPixStride);
-
-    private synchronized native void nativeWriteImage(OutputStream out, int width, int height,
-                                                      ByteBuffer rawBuffer, int rowStride,
-                                                      int pixStride) throws IOException;
-
-    private synchronized native void nativeWriteByteBuffer(OutputStream out, ByteBuffer rawBuffer,
-                                                           long offset) throws IOException;
-
-    private synchronized native void nativeWriteInputStream(OutputStream out, InputStream rawStream,
-                                                            long offset) throws IOException;
-
-    static {
-        System.loadLibrary("media_jni");
-        nativeClassInit();
-    }
-}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index d658654..90fe695 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,7 +2,6 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    android_media_DngCreator.cpp \
     android_media_ImageReader.cpp \
     android_media_MediaCrypto.cpp \
     android_media_MediaCodec.cpp \
@@ -42,7 +41,6 @@
     libjhead \
     libexif \
     libstagefright_amrnb_common \
-    libimg_utils \
 
 LOCAL_REQUIRED_MODULES := \
     libjhead_jni
@@ -55,7 +53,6 @@
     external/tremor/Tremor \
     frameworks/base/core/jni \
     frameworks/av/media/libmedia \
-    frameworks/av/media/img_utils/include \
     frameworks/av/media/libstagefright \
     frameworks/av/media/libstagefright/codecs/amrnb/enc/src \
     frameworks/av/media/libstagefright/codecs/amrnb/common \
diff --git a/media/jni/android_media_DngCreator.cpp b/media/jni/android_media_DngCreator.cpp
deleted file mode 100644
index 860d896..0000000
--- a/media/jni/android_media_DngCreator.cpp
+++ /dev/null
@@ -1,772 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "DngCreator_JNI"
-
-#include <system/camera_metadata.h>
-#include <camera/CameraMetadata.h>
-#include <img_utils/DngUtils.h>
-#include <img_utils/TagDefinitions.h>
-#include <img_utils/TiffIfd.h>
-#include <img_utils/TiffWriter.h>
-#include <img_utils/Output.h>
-
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/StrongPointer.h>
-#include <utils/RefBase.h>
-#include <cutils/properties.h>
-
-#include "android_runtime/AndroidRuntime.h"
-#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
-
-#include <jni.h>
-#include <JNIHelp.h>
-
-using namespace android;
-using namespace img_utils;
-
-#define BAIL_IF_INVALID(expr, jnienv, tagId) \
-    if ((expr) != OK) { \
-        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
-                "Invalid metadata for tag %x", tagId); \
-        return; \
-    }
-
-#define BAIL_IF_EMPTY(entry, jnienv, tagId) \
-    if (entry.count == 0) { \
-        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
-                "Missing metadata fields for tag %x", tagId); \
-        return; \
-    }
-
-#define ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
-
-static struct {
-    jfieldID mNativeContext;
-} gDngCreatorClassInfo;
-
-static struct {
-    jmethodID mWriteMethod;
-} gOutputStreamClassInfo;
-
-enum {
-    BITS_PER_SAMPLE = 16,
-    BYTES_PER_SAMPLE = 2,
-    TIFF_IFD_0 = 0
-};
-
-// ----------------------------------------------------------------------------
-
-// This class is not intended to be used across JNI calls.
-class JniOutputStream : public Output, public LightRefBase<JniOutputStream> {
-public:
-    JniOutputStream(JNIEnv* env, jobject outStream);
-
-    virtual ~JniOutputStream();
-
-    status_t open();
-    status_t write(const uint8_t* buf, size_t offset, size_t count);
-    status_t close();
-private:
-    enum {
-        BYTE_ARRAY_LENGTH = 1024
-    };
-    jobject mOutputStream;
-    JNIEnv* mEnv;
-    jbyteArray mByteArray;
-};
-
-JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
-        mEnv(env) {
-    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
-    if (mByteArray == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
-    }
-}
-
-JniOutputStream::~JniOutputStream() {
-    mEnv->DeleteLocalRef(mByteArray);
-}
-
-status_t JniOutputStream::open() {
-    // Do nothing
-    return OK;
-}
-
-status_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) {
-    while(count > 0) {
-        size_t len = BYTE_ARRAY_LENGTH;
-        len = (count > len) ? len : count;
-        mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset));
-
-        if (mEnv->ExceptionCheck()) {
-            return BAD_VALUE;
-        }
-
-        mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray,
-                0, len);
-
-        if (mEnv->ExceptionCheck()) {
-            return BAD_VALUE;
-        }
-
-        count -= len;
-        offset += len;
-    }
-    return OK;
-}
-
-status_t JniOutputStream::close() {
-    // Do nothing
-    return OK;
-}
-
-// ----------------------------------------------------------------------------
-
-extern "C" {
-
-static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
-    ALOGV("%s:", __FUNCTION__);
-    return reinterpret_cast<TiffWriter*>(env->GetLongField(thiz,
-            gDngCreatorClassInfo.mNativeContext));
-}
-
-static void DngCreator_setCreator(JNIEnv* env, jobject thiz, sp<TiffWriter> writer) {
-    ALOGV("%s:", __FUNCTION__);
-    TiffWriter* current = DngCreator_getCreator(env, thiz);
-    if (writer != NULL) {
-        writer->incStrong((void*) DngCreator_setCreator);
-    }
-    if (current) {
-        current->decStrong((void*) DngCreator_setCreator);
-    }
-    env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext,
-            reinterpret_cast<jlong>(writer.get()));
-}
-
-static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
-    ALOGV("%s:", __FUNCTION__);
-
-    gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz,
-            ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID, "J");
-    LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL,
-            "can't find android/media/DngCreator.%s", ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID);
-
-    jclass outputStreamClazz = env->FindClass("java/io/OutputStream");
-    LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class");
-    gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V");
-    LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method");
-}
-
-static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
-        jobject resultsPtr) {
-    ALOGV("%s:", __FUNCTION__);
-    CameraMetadata characteristics;
-    CameraMetadata results;
-    if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) {
-         jniThrowException(env, "java/lang/AssertionError",
-                "No native metadata defined for camera characteristics.");
-         return;
-    }
-    if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) {
-        jniThrowException(env, "java/lang/AssertionError",
-                "No native metadata defined for capture results.");
-        return;
-    }
-
-    sp<TiffWriter> writer = new TiffWriter();
-
-    writer->addIfd(TIFF_IFD_0);
-
-    status_t err = OK;
-
-    const uint32_t samplesPerPixel = 1;
-    const uint32_t bitsPerSample = BITS_PER_SAMPLE;
-    const uint32_t bitsPerByte = BITS_PER_SAMPLE / BYTES_PER_SAMPLE;
-    uint32_t imageWidth = 0;
-    uint32_t imageHeight = 0;
-
-    OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
-
-    // TODO: Greensplit.
-    // TODO: UniqueCameraModel
-    // TODO: Add remaining non-essential tags
-    {
-        // Set orientation
-        uint16_t orientation = 1; // Normal
-        BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
-                TAG_ORIENTATION);
-    }
-
-    {
-        // Set subfiletype
-        uint32_t subfileType = 0; // Main image
-        BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
-                TAG_NEWSUBFILETYPE);
-    }
-
-    {
-        // Set bits per sample
-        uint16_t bits = static_cast<uint16_t>(bitsPerSample);
-        BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
-                TAG_BITSPERSAMPLE);
-    }
-
-    {
-        // Set compression
-        uint16_t compression = 1; // None
-        BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
-                TAG_COMPRESSION);
-    }
-
-    {
-        // Set dimensions
-        camera_metadata_entry entry =
-                characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-        BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH);
-        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
-        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
-        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
-                TAG_IMAGEWIDTH);
-        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
-                TAG_IMAGELENGTH);
-        imageWidth = width;
-        imageHeight = height;
-    }
-
-    {
-        // Set photometric interpretation
-        uint16_t interpretation = 32803;
-        BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
-                TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION);
-    }
-
-    {
-        // Set blacklevel tags
-        camera_metadata_entry entry =
-                characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
-        BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL);
-        const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
-        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
-                TAG_BLACKLEVEL);
-
-        uint16_t repeatDim[2] = {2, 2};
-        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
-                TAG_BLACKLEVELREPEATDIM);
-    }
-
-    {
-        // Set samples per pixel
-        uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
-        BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
-                env, TAG_SAMPLESPERPIXEL);
-    }
-
-    {
-        // Set planar configuration
-        uint16_t config = 1; // Chunky
-        BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
-                env, TAG_PLANARCONFIGURATION);
-    }
-
-    {
-        // Set CFA pattern dimensions
-        uint16_t repeatDim[2] = {2, 2};
-        BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
-                env, TAG_CFAREPEATPATTERNDIM);
-    }
-
-    {
-        // Set CFA pattern
-        camera_metadata_entry entry =
-                        characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
-        BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN);
-        camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
-                static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
-                entry.data.u8[0]);
-        switch(cfa) {
-            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
-                uint8_t cfa[4] = {0, 1, 1, 2};
-                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
-                                                env, TAG_CFAPATTERN);
-                opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
-                break;
-            }
-            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
-                uint8_t cfa[4] = {1, 0, 2, 1};
-                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
-                                                env, TAG_CFAPATTERN);
-                opcodeCfaLayout = OpcodeListBuilder::CFA_GRBG;
-                break;
-            }
-            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
-                uint8_t cfa[4] = {1, 2, 0, 1};
-                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
-                                                env, TAG_CFAPATTERN);
-                opcodeCfaLayout = OpcodeListBuilder::CFA_GBRG;
-                break;
-            }
-            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
-                uint8_t cfa[4] = {2, 1, 1, 0};
-                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
-                                env, TAG_CFAPATTERN);
-                opcodeCfaLayout = OpcodeListBuilder::CFA_BGGR;
-                break;
-            }
-            default: {
-                jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
-                            "Invalid metadata for tag %d", TAG_CFAPATTERN);
-                return;
-            }
-        }
-    }
-
-    {
-        // Set CFA plane color
-        uint8_t cfaPlaneColor[3] = {0, 1, 2};
-        BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
-                env, TAG_CFAPLANECOLOR);
-    }
-
-    {
-        // Set CFA layout
-        uint16_t cfaLayout = 1;
-        BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
-                env, TAG_CFALAYOUT);
-    }
-
-    {
-        // Set DNG version information
-        uint8_t version[4] = {1, 4, 0, 0};
-        BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
-                env, TAG_DNGVERSION);
-
-        uint8_t backwardVersion[4] = {1, 1, 0, 0};
-        BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
-                env, TAG_DNGBACKWARDVERSION);
-    }
-
-    {
-        // Set whitelevel
-        camera_metadata_entry entry =
-                characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
-        BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL);
-        uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
-        BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
-                TAG_WHITELEVEL);
-    }
-
-    {
-        // Set default scale
-        uint32_t defaultScale[4] = {1, 1, 1, 1};
-        BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
-                env, TAG_DEFAULTSCALE);
-    }
-
-    bool singleIlluminant = false;
-    {
-        // Set calibration illuminants
-        camera_metadata_entry entry1 =
-            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
-        BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1);
-        camera_metadata_entry entry2 =
-            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
-        if (entry2.count == 0) {
-            singleIlluminant = true;
-        }
-        uint16_t ref1 = entry1.data.u8[0];
-
-        BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
-                TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1);
-
-        if (!singleIlluminant) {
-            uint16_t ref2 = entry2.data.u8[0];
-            BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
-                    TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2);
-        }
-    }
-
-    {
-        // Set color transforms
-        camera_metadata_entry entry1 =
-            characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
-        BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1);
-
-        int32_t colorTransform1[entry1.count * 2];
-
-        size_t ctr = 0;
-        for(size_t i = 0; i < entry1.count; ++i) {
-            colorTransform1[ctr++] = entry1.data.r[i].numerator;
-            colorTransform1[ctr++] = entry1.data.r[i].denominator;
-        }
-
-        BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1, TIFF_IFD_0),
-                env, TAG_COLORMATRIX1);
-
-        if (!singleIlluminant) {
-            camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
-            BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2);
-            int32_t colorTransform2[entry2.count * 2];
-
-            ctr = 0;
-            for(size_t i = 0; i < entry2.count; ++i) {
-                colorTransform2[ctr++] = entry2.data.r[i].numerator;
-                colorTransform2[ctr++] = entry2.data.r[i].denominator;
-            }
-
-            BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2, TIFF_IFD_0),
-                    env, TAG_COLORMATRIX2);
-        }
-    }
-
-    {
-        // Set calibration transforms
-        camera_metadata_entry entry1 =
-            characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
-        BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1);
-
-        int32_t calibrationTransform1[entry1.count * 2];
-
-        size_t ctr = 0;
-        for(size_t i = 0; i < entry1.count; ++i) {
-            calibrationTransform1[ctr++] = entry1.data.r[i].numerator;
-            calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
-        }
-
-        BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1,
-                TIFF_IFD_0), env, TAG_CAMERACALIBRATION1);
-
-        if (!singleIlluminant) {
-            camera_metadata_entry entry2 =
-                characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
-            BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2);
-            int32_t calibrationTransform2[entry2.count * 2];
-
-            ctr = 0;
-            for(size_t i = 0; i < entry2.count; ++i) {
-                calibrationTransform2[ctr++] = entry2.data.r[i].numerator;
-                calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
-            }
-
-            BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1,
-                    TIFF_IFD_0),  env, TAG_CAMERACALIBRATION2);
-        }
-    }
-
-    {
-        // Set forward transforms
-        camera_metadata_entry entry1 =
-            characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
-        BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1);
-
-        int32_t forwardTransform1[entry1.count * 2];
-
-        size_t ctr = 0;
-        for(size_t i = 0; i < entry1.count; ++i) {
-            forwardTransform1[ctr++] = entry1.data.r[i].numerator;
-            forwardTransform1[ctr++] = entry1.data.r[i].denominator;
-        }
-
-        BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
-                TIFF_IFD_0), env, TAG_FORWARDMATRIX1);
-
-        if (!singleIlluminant) {
-            camera_metadata_entry entry2 =
-                characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
-            BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2);
-            int32_t forwardTransform2[entry2.count * 2];
-
-            ctr = 0;
-            for(size_t i = 0; i < entry2.count; ++i) {
-                forwardTransform2[ctr++] = entry2.data.r[i].numerator;
-                forwardTransform2[ctr++] = entry2.data.r[i].denominator;
-            }
-
-            BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
-                    TIFF_IFD_0),  env, TAG_FORWARDMATRIX2);
-        }
-    }
-
-    {
-        // Set camera neutral
-        camera_metadata_entry entry =
-            results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
-        BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL);
-        uint32_t cameraNeutral[entry.count * 2];
-
-        size_t ctr = 0;
-        for(size_t i = 0; i < entry.count; ++i) {
-            cameraNeutral[ctr++] =
-                    static_cast<uint32_t>(entry.data.r[i].numerator);
-            cameraNeutral[ctr++] =
-                    static_cast<uint32_t>(entry.data.r[i].denominator);
-        }
-
-        BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
-                TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL);
-    }
-
-    {
-        // Setup data strips
-        // TODO: Switch to tiled implementation.
-        uint32_t offset = 0;
-        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &offset, TIFF_IFD_0), env,
-                TAG_STRIPOFFSETS);
-
-        BAIL_IF_INVALID(writer->addEntry(TAG_ROWSPERSTRIP, 1, &imageHeight, TIFF_IFD_0), env,
-                TAG_ROWSPERSTRIP);
-
-        uint32_t byteCount = imageWidth * imageHeight * bitsPerSample * samplesPerPixel /
-                bitsPerByte;
-        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPBYTECOUNTS, 1, &byteCount, TIFF_IFD_0), env,
-                TAG_STRIPBYTECOUNTS);
-    }
-
-    {
-        // Setup default crop + crop origin tags
-        uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
-        uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
-        if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
-            uint32_t defaultCropOrigin[] = {margin, margin};
-            uint32_t defaultCropSize[] = {imageWidth - margin, imageHeight - margin};
-            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
-                    TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN);
-            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
-                    TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE);
-        }
-    }
-
-    {
-        // Setup unique camera model tag
-        char model[PROPERTY_VALUE_MAX];
-        property_get("ro.product.model", model, "");
-
-        char manufacturer[PROPERTY_VALUE_MAX];
-        property_get("ro.product.manufacturer", manufacturer, "");
-
-        char brand[PROPERTY_VALUE_MAX];
-        property_get("ro.product.brand", brand, "");
-
-        String8 cameraModel(model);
-        cameraModel += "-";
-        cameraModel += manufacturer;
-        cameraModel += "-";
-        cameraModel += brand;
-
-        BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
-                reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
-                TAG_UNIQUECAMERAMODEL);
-    }
-
-    {
-        // Setup opcode List 2
-        camera_metadata_entry entry1 =
-                characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
-        BAIL_IF_EMPTY(entry1, env, TAG_OPCODELIST2);
-        uint32_t lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]);
-        uint32_t lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]);
-
-        camera_metadata_entry entry2 =
-                results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
-        BAIL_IF_EMPTY(entry2, env, TAG_OPCODELIST2);
-        if (entry2.count == lsmWidth * lsmHeight * 4) {
-
-            OpcodeListBuilder builder;
-            status_t err = builder.addGainMapsForMetadata(lsmWidth,
-                                                          lsmHeight,
-                                                          0,
-                                                          0,
-                                                          imageHeight,
-                                                          imageWidth,
-                                                          opcodeCfaLayout,
-                                                          entry2.data.f);
-            if (err == OK) {
-                size_t listSize = builder.getSize();
-                uint8_t opcodeListBuf[listSize];
-                err = builder.buildOpList(opcodeListBuf);
-                if (err == OK) {
-                    BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
-                            TIFF_IFD_0), env, TAG_OPCODELIST2);
-                } else {
-                    ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__);
-                    jniThrowRuntimeException(env, "failed to construct lens shading map opcode.");
-                }
-            } else {
-                ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
-                jniThrowRuntimeException(env, "failed to add lens shading map.");
-            }
-        } else {
-            ALOGW("%s: Lens shading map not present in results, skipping...", __FUNCTION__);
-        }
-    }
-
-    DngCreator_setCreator(env, thiz, writer);
-}
-
-static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
-    ALOGV("%s:", __FUNCTION__);
-    DngCreator_setCreator(env, thiz, NULL);
-}
-
-static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz) {
-    ALOGV("%s:", __FUNCTION__);
-    jniThrowRuntimeException(env, "nativeSetOrientation is not implemented");
-}
-
-static void DngCreator_nativeSetThumbnailBitmap(JNIEnv* env, jobject thiz, jobject bitmap) {
-    ALOGV("%s:", __FUNCTION__);
-    jniThrowRuntimeException(env, "nativeSetThumbnailBitmap is not implemented");
-}
-
-static void DngCreator_nativeSetThumbnailImage(JNIEnv* env, jobject thiz, jint width, jint height,
-        jobject yBuffer, jint yRowStride, jint yPixStride, jobject uBuffer, jint uRowStride,
-        jint uPixStride, jobject vBuffer, jint vRowStride, jint vPixStride) {
-    ALOGV("%s:", __FUNCTION__);
-    jniThrowRuntimeException(env, "nativeSetThumbnailImage is not implemented");
-}
-
-static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width,
-        jint height, jobject inBuffer, jint rowStride, jint pixStride) {
-    ALOGV("%s:", __FUNCTION__);
-
-    sp<JniOutputStream> out = new JniOutputStream(env, outStream);
-    if(env->ExceptionCheck()) {
-        ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
-        return;
-    }
-
-    uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
-    if (pixelBytes == NULL) {
-        ALOGE("%s: Could not get native byte buffer", __FUNCTION__);
-        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid bytebuffer");
-        return;
-    }
-
-    TiffWriter* writer = DngCreator_getCreator(env, thiz);
-    if (writer == NULL) {
-        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
-        jniThrowException(env, "java/lang/AssertionError",
-                "Write called with uninitialized DngCreator");
-        return;
-    }
-    // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
-    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, TIFF_IFD_0)->getData<uint32_t>());
-    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, TIFF_IFD_0)->getData<uint32_t>());
-    if (metadataWidth != width) {
-        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
-                        "Metadata width %d doesn't match image width %d", metadataWidth, width);
-        return;
-    }
-
-    if (metadataHeight != height) {
-        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
-                        "Metadata height %d doesn't match image height %d", metadataHeight, height);
-        return;
-    }
-
-    uint32_t stripOffset = writer->getTotalSize();
-
-    BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &stripOffset, TIFF_IFD_0), env,
-                    TAG_STRIPOFFSETS);
-
-    if (writer->write(out.get()) != OK) {
-        if (!env->ExceptionCheck()) {
-            jniThrowException(env, "java/io/IOException", "Failed to write metadata");
-        }
-        return;
-    }
-
-    size_t fullSize = rowStride * height;
-    jlong capacity = env->GetDirectBufferCapacity(inBuffer);
-    if (capacity < 0 || fullSize > capacity) {
-        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
-                "Invalid size %d for Image, size given in metadata is %d at current stride",
-                capacity, fullSize);
-        return;
-    }
-
-    if (pixStride == BYTES_PER_SAMPLE && rowStride == width * BYTES_PER_SAMPLE) {
-        if (out->write(pixelBytes, 0, fullSize) != OK || env->ExceptionCheck()) {
-            if (!env->ExceptionCheck()) {
-                jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
-            }
-            return;
-        }
-    } else if (pixStride == BYTES_PER_SAMPLE) {
-        for (size_t i = 0; i < height; ++i) {
-            if (out->write(pixelBytes, i * rowStride, pixStride * width) != OK ||
-                        env->ExceptionCheck()) {
-                if (!env->ExceptionCheck()) {
-                    jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
-                }
-                return;
-            }
-        }
-    } else {
-        for (size_t i = 0; i < height; ++i) {
-            for (size_t j = 0; j < width; ++j) {
-                if (out->write(pixelBytes, i * rowStride + j * pixStride,
-                        BYTES_PER_SAMPLE) != OK || !env->ExceptionCheck()) {
-                    if (env->ExceptionCheck()) {
-                        jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
-                    }
-                    return;
-                }
-            }
-        }
-    }
-
-}
-
-static void DngCreator_nativeWriteByteBuffer(JNIEnv* env, jobject thiz, jobject outStream,
-        jobject rawBuffer, jlong offset) {
-    ALOGV("%s:", __FUNCTION__);
-    jniThrowRuntimeException(env, "nativeWriteByteBuffer is not implemented.");
-}
-
-static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream,
-        jobject inStream, jlong offset) {
-    ALOGV("%s:", __FUNCTION__);
-    jniThrowRuntimeException(env, "nativeWriteInputStream is not implemented.");
-}
-
-} /*extern "C" */
-
-static JNINativeMethod gDngCreatorMethods[] = {
-    {"nativeClassInit",        "()V", (void*) DngCreator_nativeClassInit},
-    {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
-            "Landroid/hardware/camera2/impl/CameraMetadataNative;)V", (void*) DngCreator_init},
-    {"nativeDestroy",           "()V",      (void*) DngCreator_destroy},
-    {"nativeSetOrientation",    "(I)V",     (void*) DngCreator_nativeSetOrientation},
-    {"nativeSetThumbnailBitmap","(Landroid/graphics/Bitmap;)V",
-            (void*) DngCreator_nativeSetThumbnailBitmap},
-    {"nativeSetThumbnailImage",
-            "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)V",
-            (void*) DngCreator_nativeSetThumbnailImage},
-    {"nativeWriteImage",        "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;II)V",
-            (void*) DngCreator_nativeWriteImage},
-    {"nativeWriteByteBuffer",    "(Ljava/io/OutputStream;Ljava/nio/ByteBuffer;J)V",
-            (void*) DngCreator_nativeWriteByteBuffer},
-    {"nativeWriteInputStream",    "(Ljava/io/OutputStream;Ljava/io/InputStream;J)V",
-            (void*) DngCreator_nativeWriteInputStream},
-};
-
-int register_android_media_DngCreator(JNIEnv *env) {
-    return AndroidRuntime::registerNativeMethods(env,
-                   "android/media/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods));
-}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 9d03cc3..6f42057 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -884,7 +884,6 @@
                 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
 }
 
-extern int register_android_media_DngCreator(JNIEnv *env);
 extern int register_android_media_ImageReader(JNIEnv *env);
 extern int register_android_media_Crypto(JNIEnv *env);
 extern int register_android_media_Drm(JNIEnv *env);
@@ -914,11 +913,6 @@
     }
     assert(env != NULL);
 
-    if (register_android_media_DngCreator(env) < 0) {
-        ALOGE("ERROR: ImageReader native registration failed");
-        goto bail;
-    }
-
     if (register_android_media_ImageReader(env) < 0) {
         ALOGE("ERROR: ImageReader native registration failed");
         goto bail;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index a77b647..a3caba2 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -17,6 +17,7 @@
 package com.android.mediaframeworktest.unit;
 
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
 import android.util.Range;
 import android.util.Rational;
 import android.util.SizeF;
@@ -26,6 +27,8 @@
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.util.Size;
 import android.hardware.camera2.impl.CameraMetadataNative;
@@ -46,6 +49,7 @@
 import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.List;
 
 /**
  * <pre>
@@ -56,6 +60,10 @@
  */
 public class CameraMetadataTest extends junit.framework.TestCase {
 
+    private static final boolean VERBOSE = false;
+    private static final String TAG = "CameraMetadataTest";
+
+
     CameraMetadataNative mMetadata;
 
     // Sections
@@ -940,7 +948,7 @@
         };
         int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats");
 
-        Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS;
+        Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey();
 
         validateArrayMetadataReadWriteOverride(formatKey, availableFormats,
                 expectedIntValues, availableFormatTag);
@@ -1046,7 +1054,7 @@
                 0x20, 320, 240, INPUT,   // RAW16
         };
         Key<StreamConfiguration[]> configKey =
-                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS.getNativeKey();
         mMetadata.writeValues(configKey.getTag(),
                 toByteArray(rawAvailableStreamConfigs));
 
@@ -1074,7 +1082,7 @@
                 0x21, 1920, 1080, 33333338  // BLOB
         };
         Key<StreamConfigurationDuration[]> durationKey =
-                CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+                CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS.getNativeKey();
         mMetadata.writeValues(durationKey.getTag(),
                 toByteArray(rawAvailableMinDurations));
 
@@ -1100,7 +1108,7 @@
                 0x21, 1920, 1080, 33333338  // BLOB
         };
         Key<StreamConfigurationDuration[]> stallDurationKey =
-                CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS;
+                CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS.getNativeKey();
         mMetadata.writeValues(stallDurationKey.getTag(),
                 toByteArray(rawAvailableStallDurations));
 
@@ -1158,6 +1166,31 @@
         }
     }
 
+    @SmallTest
+    public void testCaptureResult() {
+        mMetadata.set(CaptureRequest.CONTROL_AE_MODE,
+                CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH);
+
+        if (VERBOSE) mMetadata.dumpToLog();
+
+        CaptureResult captureResult = new CaptureResult(mMetadata, /*sequenceId*/0);
+
+        List<CaptureResult.Key<?>> allKeys = captureResult.getKeys();
+        if (VERBOSE) Log.v(TAG, "testCaptureResult: key list size " + allKeys);
+        for (CaptureResult.Key<?> key : captureResult.getKeys()) {
+            if (VERBOSE) {
+                Log.v(TAG,
+                    "testCaptureResult: key " + key + " value" + captureResult.get(key));
+            }
+        }
+
+        assertTrue(allKeys.size() >= 1); // FIXME: android.statistics.faces counts as a key
+        assertTrue(allKeys.contains(CaptureResult.CONTROL_AE_MODE));
+
+        assertEquals(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH,
+                (int)captureResult.get(CaptureResult.CONTROL_AE_MODE));
+    }
+
     private static void checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap,
             int format, int width, int height,
             boolean output) {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index acfcd83..3f37ed1 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -171,8 +171,3 @@
 {
     return static_cast<Sensor const*>(sensor)->getStringType().string();
 }
-
-const char* ASensor_getRequiredPermission(ASensor const* sensor)
-{
-    return static_cast<Sensor const*>(sensor)->getRequiredPermission().string();
-}
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index f0f7e10..24d66ce 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -27,7 +27,7 @@
     <string name="menu_settings" msgid="6008033148948428823">"Ρυθμίσεις"</string>
     <string name="menu_open" msgid="432922957274920903">"Άνοιγμα"</string>
     <string name="menu_save" msgid="2394743337684426338">"Αποθήκευση"</string>
-    <string name="menu_share" msgid="3075149983979628146">"Κοινοποίηση"</string>
+    <string name="menu_share" msgid="3075149983979628146">"Κοινή χρήση"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Διαγραφή"</string>
     <string name="menu_select" msgid="8711270657353563424">"Επιλογή \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Επιλέχθηκαν <xliff:g id="COUNT">%1$d</xliff:g>"</string>
@@ -51,5 +51,5 @@
     <string name="empty" msgid="7858882803708117596">"Δεν υπάρχουν στοιχεία"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
-    <string name="share_via" msgid="8966594246261344259">"Κοινοποίηση μέσω"</string>
+    <string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 8c9030d..e8944ec 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -20,14 +20,14 @@
     <string name="title_open" msgid="4353228937663917801">"បើក​ពី"</string>
     <string name="title_save" msgid="2433679664882857999">"រក្សា​ទុក​ទៅ"</string>
     <string name="menu_create_dir" msgid="5947289605844398389">"បង្កើត​ថត"</string>
-    <string name="menu_grid" msgid="6878021334497835259">"ទិដ្ឋភាព​ក្រឡា​"</string>
+    <string name="menu_grid" msgid="6878021334497835259">"ទិដ្ឋភាព​ក្រឡា"</string>
     <string name="menu_list" msgid="7279285939892417279">"ទិដ្ឋភាព​បញ្ជី"</string>
     <string name="menu_sort" msgid="7677740407158414452">"តម្រៀប​តាម"</string>
     <string name="menu_search" msgid="3816712084502856974">"ស្វែងរក"</string>
     <string name="menu_settings" msgid="6008033148948428823">"ការ​កំណត់"</string>
     <string name="menu_open" msgid="432922957274920903">"បើក"</string>
     <string name="menu_save" msgid="2394743337684426338">"រក្សាទុក"</string>
-    <string name="menu_share" msgid="3075149983979628146">"ចែករំលែក​"</string>
+    <string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string>
     <string name="menu_delete" msgid="8138799623850614177">"លុប"</string>
     <string name="menu_select" msgid="8711270657353563424">"ជ្រើស \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"បាន​ជ្រើស <xliff:g id="COUNT">%1$d</xliff:g>"</string>
@@ -48,7 +48,7 @@
     <string name="pref_advanced_devices" msgid="903257239609301276">"បង្ហាញ​ឧបករណ៍​កម្រិត​ខ្ពស់"</string>
     <string name="pref_file_size" msgid="2826879315743961459">"បង្ហាញ​ទំហំ​ឯកសារ"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"បង្ហាញ​ទំហំ​ឧបករណ៍"</string>
-    <string name="empty" msgid="7858882803708117596">"គ្មានធាតុ​"</string>
+    <string name="empty" msgid="7858882803708117596">"គ្មានធាតុ"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"មិន​អាច​បើក​ឯកសារ"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"មិន​អាច​លុប​ឯកសារ​មួយ​ចំនួន"</string>
     <string name="share_via" msgid="8966594246261344259">"ចែករំលែក​តាម"</string>
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index 45d1e2a..d67a9fd 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeus"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litaus"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latyn)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letties"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 3f62df6..3e84794 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ዕብራስጥ"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ሊቱዌኒያኛ"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ስፓኒሽ (ላቲን)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"ላትቪያኛ"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index e70cad4..a922a46 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"العبرية"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"الليتوانية"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"الإسبانية (اللاتينية)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"اللاتفية"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index 7582a69..d68a347 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ивритска клавиатурна подредба"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовска клавиатурна подредба"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Исп. клав. подредба (Лат. Америка)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"латвийски"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index e38b9a8..6baa5b8 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreu"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituà"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanyol (llatí)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letó"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 532f3c0..1c502fe 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejština"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litevština"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španělština (Latinská Amerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lotyšská klávesnice"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 3c907f8..043a5b3 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebræisk"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisk"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinamerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lettisk"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index 83be031..04c19e3 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebräisch"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisch"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanisch (Lateinisch)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lettisch"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 99f77ed..025a288 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Εβραϊκά"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Λιθουανικά"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ισπανικά (Λατινικής Αμερικής)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Λετονικά"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index e22c675..d5797a0 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index e22c675..d5797a0 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 5190fc5..0a9d2f3 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (latino)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letón"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index a81ed29..6e41abf 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (Latinoamérica)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letón"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-et-rEE/strings.xml b/packages/InputDevices/res/values-et-rEE/strings.xml
index b90f825..0d931ce 100644
--- a/packages/InputDevices/res/values-et-rEE/strings.xml
+++ b/packages/InputDevices/res/values-et-rEE/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Heebrea"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Leedu"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Hispaania (Ladina-Ameerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"läti keel"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index 490b5c2..e87fbad 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"عبری"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"لیتوانیایی"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"اسپانیایی (لاتین)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"لتونیایی"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index 060d0e7..5b39dfd 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"heprea"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"liettua"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"espanja (Latinalainen Amerikka)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvialainen"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index 8fc9f79..9973918 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hébreu"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituanien"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letton"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index b029b02..fa2977b 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hébreu"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituanien"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letton"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index 8398c92..77cb8fe 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"हिब्रू"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"लिथुआनियाई"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"स्पेनिश (लैटिन)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"लातवियाई"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 68c868f..bad973d 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejski"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litavski"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španjolski (Latinska Amerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvijska"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index af6a571..510591d 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"héber"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litván"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"spanyol (latin-amerikai)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"lett"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hy-rAM/strings.xml b/packages/InputDevices/res/values-hy-rAM/strings.xml
index 068e559..9ffa8bb 100644
--- a/packages/InputDevices/res/values-hy-rAM/strings.xml
+++ b/packages/InputDevices/res/values-hy-rAM/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Եբրայերեն"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Լիտվերեն"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Իսպաներեն (Լատինական)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"լատիշերեն"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index d32ac98..fccfa67 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ibrani"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuania"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanyol (Latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvi"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index 280a23c..83dba70 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ebraico"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spagnolo (America Latina)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lettone"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 9bb66d8..26fe662 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"עברית"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ליטאית"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ספרדית (לטינית)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"לטבית"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 26b1094..e2b154d 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ヘブライ語"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"リトアニア語"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"スペイン語(中南米)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"ラトビア語"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ka-rGE/strings.xml b/packages/InputDevices/res/values-ka-rGE/strings.xml
index 35085a1..eff4b04 100644
--- a/packages/InputDevices/res/values-ka-rGE/strings.xml
+++ b/packages/InputDevices/res/values-ka-rGE/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ებრაული"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ლიტვური"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ესპანური (ლათინური)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"ლატვიური"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-km-rKH/strings.xml b/packages/InputDevices/res/values-km-rKH/strings.xml
index ea3b755..60a28b1 100644
--- a/packages/InputDevices/res/values-km-rKH/strings.xml
+++ b/packages/InputDevices/res/values-km-rKH/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"អ៊ីស្រាអែល"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"លីទុយអានី"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"អេស្ប៉ាញ (ឡាតាំង​)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"ឡាតវីយ៉ា"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index e360ed0..3f563d1 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"히브리어"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"리투아니아어"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"스페인어(라틴)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"라트비아어"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lo-rLA/strings.xml b/packages/InputDevices/res/values-lo-rLA/strings.xml
index fc37501..fb3fe17 100644
--- a/packages/InputDevices/res/values-lo-rLA/strings.xml
+++ b/packages/InputDevices/res/values-lo-rLA/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ຮີບຣິວ"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"​ລິ​ທົວ​ນຽນ"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"​ສະ​ແປນ​ນິດ (ລາ​ຕິນ)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"​ລັດ​ວຽນ"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index c197389..d0eb1f6 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrajų"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuvių"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ispanų (Lotynų Amerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvių k."</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 53d2467..0608bf0 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ivrits"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuviešu"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spāņu (latīņu)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latviešu"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-mn-rMN/strings.xml b/packages/InputDevices/res/values-mn-rMN/strings.xml
index 194c577..a28fd2a 100644
--- a/packages/InputDevices/res/values-mn-rMN/strings.xml
+++ b/packages/InputDevices/res/values-mn-rMN/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Еврей"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литви"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испани (Латин)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латви"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ms-rMY/strings.xml b/packages/InputDevices/res/values-ms-rMY/strings.xml
index a3098c5..a1a6d00 100644
--- a/packages/InputDevices/res/values-ms-rMY/strings.xml
+++ b/packages/InputDevices/res/values-ms-rMY/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Bahasa Ibrani"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Bahasa Lithuania"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Bahasa Sepanyol (Latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Bahasa Latvia"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index 47cff5c..ad4b704 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraisk"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisk"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinsk)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvisk"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index e858c9c..c57251e 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeuws"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litouws"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latijns-Amerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lets"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 0ca91ca..39fb3ec 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrajski"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litewski"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"hiszpański (Ameryka Łacińska)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"łotewski"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index d5afe05..3ac3b84 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letão"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index 84cf865..e9a0a38 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letão"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index 5278643..c2392b1 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ebraică"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniană"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaniolă (America Latină)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letonă"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 3ae2e53..70ecf6e 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Иврит"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовский"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испанский (Латинская Америка)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"латышский"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index 1e51167..d2ee0cf 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrejčina"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litovčina"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Španielčina (Latinská Amerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Lotyština"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index 66e340e..38542ef 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejščina"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litovščina"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španščina (Latinska Amerika)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"latvijščina"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 14ccbf3..dd500e6 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"хебрејски"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"литвански"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"шпански (Латинска Америка)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"летонски"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index f3338c6..c2406c0 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreiska"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauiska"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanska (latinamerikansk)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"lettiska"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 336cc33..f71a696 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Kiyahudi"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Kilithuania"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Kihispania (Kilatini)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Kilatvia"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 86a633a..296994b 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ฮิบรู"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ลิทัวเนีย"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"สเปน (ละติน)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"ลัตเวีย"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index 702a0cb..d7920ed 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index b3ce0a3..c0c70be 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"İbranice"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litvanca"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"İspanyolca (Latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letonca"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index 5193a90..d8152d4 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Іврит"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовська"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Іспанська (латиниця)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Латвійська"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index 2240100..a90c1cd 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Tiếng Do Thái"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Tiếng Lithuania"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Tiếng Tây Ban Nha (La tinh)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Tiếng Latvia"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index 161b600..206f97c 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯来语"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛语"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙语(拉丁美洲)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"拉脱维亚语"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index f0df88c..ff5570e 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"拉脫維亞文"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index ca43326..859983d 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"拉脫維亞文"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 677ed29..9f30f7a 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -39,6 +39,5 @@
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Isi-Hebrew"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Isi-Lithuanian"</string>
     <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Isi-Spanish (Latin)"</string>
-    <!-- no translation found for keyboard_layout_latvian (4405417142306250595) -->
-    <skip />
+    <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Isi-Latvian"</string>
 </resources>
diff --git a/packages/Keyguard/res/layout/keyguard_bouncer.xml b/packages/Keyguard/res/layout/keyguard_bouncer.xml
index 975a139..489c5f5 100644
--- a/packages/Keyguard/res/layout/keyguard_bouncer.xml
+++ b/packages/Keyguard/res/layout/keyguard_bouncer.xml
@@ -18,12 +18,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <View android:id="@+id/bouncer_background"
-        android:background="#cc000000"
-        android:clickable="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
-
     <include
         style="@style/BouncerSecurityContainer"
         layout="@layout/keyguard_simple_host_view"
diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
index b2d0219..78b5746 100644
--- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -37,6 +37,7 @@
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textSize="@dimen/kg_status_line_font_size"
         android:textColor="?android:attr/textColorSecondary"
+        android:visibility="gone"
         androidprv:allCaps="@bool/kg_use_all_caps" />
 
     <LinearLayout
diff --git a/packages/Keyguard/res/layout/keyguard_pin_view.xml b/packages/Keyguard/res/layout/keyguard_pin_view.xml
index a804c8c..a8e330b 100644
--- a/packages/Keyguard/res/layout/keyguard_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pin_view.xml
@@ -41,28 +41,16 @@
        android:layout_weight="1"
        android:layoutDirection="ltr"
        >
-       <LinearLayout
+       <RelativeLayout
+          android:id="@+id/row0"
           android:layout_width="match_parent"
           android:layout_height="0dp"
-          android:orientation="horizontal"
           android:layout_weight="1"
           >
-          <TextView android:id="@+id/pinEntry"
-               android:editable="true"
-               android:layout_width="0dip"
-               android:layout_height="match_parent"
-               android:layout_weight="1"
-               android:gravity="center"
-               android:layout_marginStart="@dimen/keyguard_lockscreen_pin_margin_left"
-               android:singleLine="true"
-               android:cursorVisible="false"
-               android:background="@null"
-               android:textAppearance="@style/TextAppearance.NumPadKey"
-               android:imeOptions="flagForceAscii|actionDone"
-               />
-           <ImageButton android:id="@+id/delete_button"
+          <ImageButton android:id="@+id/delete_button"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
+               android:layout_alignParentEnd="true"
                android:gravity="center_vertical"
                android:src="@drawable/ic_input_delete"
                android:clickable="true"
@@ -73,13 +61,30 @@
                android:background="?android:attr/selectableItemBackground"
                android:contentDescription="@string/keyboardview_keycode_delete"
                />
-       </LinearLayout>
-       <View
-           android:layout_width="wrap_content"
-           android:layout_height="1dp"
-           android:background="#55FFFFFF"
-           />
+           <TextView android:id="@+id/pinEntry"
+               android:editable="true"
+               android:layout_width="match_parent"
+               android:layout_height="match_parent"
+               android:layout_toStartOf="@+id/delete_button"
+               android:layout_alignParentStart="true"
+               android:gravity="center"
+               android:layout_marginStart="@dimen/keyguard_lockscreen_pin_margin_left"
+               android:singleLine="true"
+               android:cursorVisible="false"
+               android:background="@null"
+               android:textAppearance="@style/TextAppearance.NumPadKey"
+               android:imeOptions="flagForceAscii|actionDone"
+               />
+            <View
+               android:id="@+id/divider"
+               android:layout_width="match_parent"
+               android:layout_height="1dp"
+               android:layout_alignParentBottom="true"
+               android:background="#55FFFFFF"
+               />
+       </RelativeLayout>
        <LinearLayout
+           android:id="@+id/row1"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
@@ -114,6 +119,7 @@
                />
        </LinearLayout>
        <LinearLayout
+           android:id="@+id/row2"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
@@ -148,6 +154,7 @@
                />
        </LinearLayout>
        <LinearLayout
+           android:id="@+id/row3"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:orientation="horizontal"
@@ -182,6 +189,7 @@
                />
        </LinearLayout>
        <LinearLayout
+           android:id="@+id/row4"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index f79819f..112e371a 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -39,13 +39,12 @@
             android:id="@+id/clock_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal|top"
+            android:layout_gravity="center_horizontal"
             android:textColor="@color/clock_white"
             android:singleLine="true"
             style="@style/widget_big_thin"
             android:format12Hour="@string/keyguard_widget_12_hours_format"
             android:format24Hour="@string/keyguard_widget_24_hours_format"
-            android:baselineAligned="true"
             android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
 
         <include layout="@layout/keyguard_status_area" />
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index 18b59f1..a2e54a7 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -83,7 +83,7 @@
     <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
     <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះ​បង់​"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះ​បង់"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"រួចរាល់"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ប្ដូរ​របៀប"</string>
@@ -120,7 +120,7 @@
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាម​លំនាំ​ច្រើន​ពេក"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"ដើម្បី​ដោះ​សោ ចូល​ក្នុង​គណនី Google ។"</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"ឈ្មោះ​អ្នក​ប្រើ (អ៊ី​ម៉ែ​ល​)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់​"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"ចូល"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ។"</string>
     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ភ្លេច​ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​របស់​អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index 5615ff7..13a6f62 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -26,5 +26,4 @@
 
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">88dp</dimen>
-    <dimen name="bottom_text_spacing_digital">-24dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index a5e93dc..b954792 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -65,7 +65,7 @@
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">96dp</dimen>
     <dimen name="widget_label_font_size">16sp</dimen>
-    <dimen name="bottom_text_spacing_digital">-24dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-8dp</dimen>
 
     <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
          Should be 0 on devices with plenty of room (e.g. tablets) -->
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 6224aed..01d9ab3 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -155,10 +155,12 @@
     <dimen name="eca_overlap">-10dip</dimen>
 
     <!-- Default clock parameters -->
-    <dimen name="bottom_text_spacing_digital">-18dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-6dp</dimen>
     <dimen name="label_font_size">14dp</dimen>
     <dimen name="widget_label_font_size">14sp</dimen>
     <dimen name="widget_big_font_size">68dp</dimen>
     <dimen name="big_font_size">120dp</dimen>
 
+    <!-- The y translation to apply at the start in appear animations. -->
+    <dimen name="appear_y_translation_start">24dp</dimen>
 </resources>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index d20b269..8cf07fa 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -97,9 +97,9 @@
     <string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
 
     <!-- Time format strings for fall-back clock widget -->
-    <string name="keyguard_widget_12_hours_format" translatable="false">h&#58;mm</string>
+    <string name="keyguard_widget_12_hours_format" translatable="false">h\uee01mm</string>
     <!-- Time format strings for fall-back clock widget -->
-    <string name="keyguard_widget_24_hours_format" translatable="false">kk&#58;mm</string>
+    <string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string>
 
     <!-- Accessibility description sent when user changes the current lock screen widget. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_widget_changed">%1$s. Widget %2$d of %3$d.</string>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index 5ab00d2..11142cf 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -59,8 +59,6 @@
 
     <!-- Built-in clock widget stuff -->
     <style name="widget_label">
-        <item name="android:textStyle">bold</item>
-        <item name="android:fontFamily">sans-serif-light</item>
         <item name="android:textSize">@dimen/widget_label_font_size</item>
     </style>
     <style name="big_thin">
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
new file mode 100644
index 0000000..ea896d5
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
@@ -0,0 +1,99 @@
+/*
+ * 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.keyguard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+/**
+ * A class to make nice appear transitions for views in a tabular layout.
+ */
+public class AppearAnimationUtils {
+
+    public static final long APPEAR_DURATION = 220;
+
+    private final Interpolator mLinearOutSlowIn;
+    private final float mStartTranslation;
+
+    public AppearAnimationUtils(Context ctx) {
+        mLinearOutSlowIn = AnimationUtils.loadInterpolator(
+                ctx, android.R.interpolator.linear_out_slow_in);
+        mStartTranslation =
+                ctx.getResources().getDimensionPixelOffset(R.dimen.appear_y_translation_start);
+    }
+
+    public void startAppearAnimation(View[][] views, final Runnable finishListener) {
+        long maxDelay = 0;
+        ViewPropertyAnimator maxDelayAnimator = null;
+        for (int row = 0; row < views.length; row++) {
+            View[] columns = views[row];
+            for (int col = 0; col < columns.length; col++) {
+                long delay = calculateDelay(row, col);
+                ViewPropertyAnimator animator = startAppearAnimation(columns[col], delay);
+                if (animator != null && delay > maxDelay) {
+                    maxDelay = delay;
+                    maxDelayAnimator = animator;
+                }
+            }
+        }
+        if (maxDelayAnimator != null) {
+            maxDelayAnimator.setListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    finishListener.run();
+                }
+            });
+        } else {
+            finishListener.run();
+        }
+    }
+
+    private ViewPropertyAnimator startAppearAnimation(View view, long delay) {
+        if (view == null) return null;
+        view.setAlpha(0f);
+        view.setTranslationY(mStartTranslation);
+        view.animate()
+                .alpha(1f)
+                .translationY(0)
+                .setInterpolator(mLinearOutSlowIn)
+                .setDuration(APPEAR_DURATION)
+                .setStartDelay(delay)
+                .setListener(null);
+        if (view.hasOverlappingRendering()) {
+            view.animate().withLayer();
+        }
+        return view.animate();
+    }
+
+    private long calculateDelay(int row, int col) {
+        return (long) (row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20);
+    }
+
+    public TimeInterpolator getInterpolator() {
+        return mLinearOutSlowIn;
+    }
+
+    public float getStartTranslation() {
+        return mStartTranslation;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyCarrierArea.java b/packages/Keyguard/src/com/android/keyguard/EmergencyCarrierArea.java
index 6d392fc..a592db9 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyCarrierArea.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyCarrierArea.java
@@ -17,13 +17,12 @@
 package com.android.keyguard;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.LinearLayout;
 
-import com.android.keyguard.R;
-
 public class EmergencyCarrierArea extends LinearLayout {
 
     private CarrierText mCarrierText;
@@ -48,6 +47,7 @@
         mEmergencyButton.setOnTouchListener(new OnTouchListener(){
             @Override
             public boolean onTouch(View v, MotionEvent event) {
+                if (mCarrierText.getVisibility() != View.VISIBLE) return false;
                 switch(event.getAction()) {
                     case MotionEvent.ACTION_DOWN:
                         mCarrierText.animate().alpha(0);
@@ -59,4 +59,8 @@
                 return false;
             }});
     }
+
+    public void setCarrierTextVisible(boolean visible) {
+        mCarrierText.setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java
index f69fa5f..69abc7a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java
@@ -328,5 +328,10 @@
     @Override
     public void hideBouncer(int duration) {
     }
+
+    @Override
+    public void startAppearAnimation() {
+        // TODO.
+    }
 }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
index 701d15f..c9fe93c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -349,4 +349,8 @@
                 hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
     }
 
+    @Override
+    public void startAppearAnimation() {
+        // TODO.
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
index ede23ef..d589283 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
@@ -48,35 +48,19 @@
      */
     private static final long ANNOUNCEMENT_DELAY = 250;
 
-    static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging;
-    static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery;
-
     static final int SECURITY_MESSAGE_DURATION = 5000;
     protected static final int FADE_DURATION = 750;
 
     private static final String TAG = "KeyguardMessageArea";
 
-    // are we showing battery information?
-    boolean mShowingBatteryInfo = false;
-
     // is the bouncer up?
     boolean mShowingBouncer = false;
 
-    // last known plugged in state
-    boolean mCharging = false;
-
-    // last known battery level
-    int mBatteryLevel = 100;
-
     KeyguardUpdateMonitor mUpdateMonitor;
 
     // Timeout before we reset the message to show charging/owner info
     long mTimeout = SECURITY_MESSAGE_DURATION;
 
-    // Shadowed text values
-    protected boolean mBatteryCharged;
-    protected boolean mBatteryIsLow;
-
     private Handler mHandler;
 
     CharSequence mMessage;
@@ -146,16 +130,6 @@
     }
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
-            mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow();
-            mCharging = status.status == BatteryManager.BATTERY_STATUS_CHARGING
-                     || status.status == BatteryManager.BATTERY_STATUS_FULL;
-            mBatteryLevel = status.level;
-            mBatteryCharged = status.isCharged();
-            mBatteryIsLow = status.isBatteryLow();
-            update();
-        }
         public void onScreenTurnedOff(int why) {
             setSelected(false);
         };
@@ -212,7 +186,7 @@
      */
     void update() {
         MutableInt icon = new MutableInt(0);
-        CharSequence status = concat(getChargeInfo(icon), getOwnerInfo(), getCurrentMessage());
+        CharSequence status = concat(getOwnerInfo(), getCurrentMessage());
         setCompoundDrawablesWithIntrinsicBounds(icon.value, 0, 0, 0);
         setText(status);
     }
@@ -248,25 +222,6 @@
         return info;
     }
 
-    private CharSequence getChargeInfo(MutableInt icon) {
-        CharSequence string = null;
-        if (mShowingBatteryInfo && !mShowingMessage) {
-            // Battery status
-            if (mCharging) {
-                // Charging, charged or waiting to charge.
-                string = getContext().getString(mBatteryCharged
-                        ? R.string.keyguard_charged
-                        : R.string.keyguard_plugged_in, mBatteryLevel);
-                icon.value = CHARGING_ICON;
-            } else if (mBatteryIsLow) {
-                // Battery is low
-                string = getContext().getString(R.string.keyguard_low_battery);
-                icon.value = BATTERY_LOW_ICON;
-            }
-        }
-        return string;
-    }
-
     private void hideMessage(int duration, boolean thenUpdate) {
         if (duration > 0) {
             Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index ca2d615..1f3c176 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -22,6 +22,7 @@
 import android.text.method.DigitsKeyListener;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.TextView.OnEditorActionListener;
 
 /**
@@ -30,12 +31,21 @@
 public class KeyguardPINView extends KeyguardAbsKeyInputView
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
 
+    private final AppearAnimationUtils mAppearAnimationUtils;
+    private ViewGroup mKeyguardBouncerFrame;
+    private ViewGroup mRow0;
+    private ViewGroup mRow1;
+    private ViewGroup mRow2;
+    private ViewGroup mRow3;
+    private View mDivider;
+
     public KeyguardPINView(Context context) {
         this(context, null);
     }
 
     public KeyguardPINView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mAppearAnimationUtils = new AppearAnimationUtils(context);
     }
 
     protected void resetState() {
@@ -56,6 +66,12 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
+        mKeyguardBouncerFrame = (ViewGroup) findViewById(R.id.keyguard_bouncer_frame);
+        mRow0 = (ViewGroup) findViewById(R.id.row0);
+        mRow1 = (ViewGroup) findViewById(R.id.row1);
+        mRow2 = (ViewGroup) findViewById(R.id.row2);
+        mRow3 = (ViewGroup) findViewById(R.id.row3);
+        mDivider = findViewById(R.id.divider);
         final View ok = findViewById(R.id.key_enter);
         if (ok != null) {
             ok.setOnClickListener(new View.OnClickListener() {
@@ -114,4 +130,48 @@
     public int getWrongPasswordStringId() {
         return R.string.kg_wrong_pin;
     }
+
+    @Override
+    public void startAppearAnimation() {
+        enableClipping(false);
+        setTranslationY(mAppearAnimationUtils.getStartTranslation());
+        animate()
+                .setDuration(500)
+                .setInterpolator(mAppearAnimationUtils.getInterpolator())
+                .translationY(0);
+        mAppearAnimationUtils.startAppearAnimation(new View[][] {
+                new View[] {
+                        mRow0, null, null
+                },
+                new View[] {
+                        findViewById(R.id.key1), findViewById(R.id.key2), findViewById(R.id.key3)
+                },
+                new View[] {
+                        findViewById(R.id.key4), findViewById(R.id.key5), findViewById(R.id.key6)
+                },
+                new View[] {
+                        findViewById(R.id.key7), findViewById(R.id.key8), findViewById(R.id.key9)
+                },
+                new View[] {
+                        null, findViewById(R.id.key0), findViewById(R.id.key_enter)
+                },
+                new View[] {
+                        null, mEcaView, null
+                }},
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        enableClipping(true);
+                    }
+                });
+    }
+
+    private void enableClipping(boolean enable) {
+        mKeyguardBouncerFrame.setClipToPadding(enable);
+        mKeyguardBouncerFrame.setClipChildren(enable);
+        mRow1.setClipToPadding(enable);
+        mRow2.setClipToPadding(enable);
+        mRow3.setClipToPadding(enable);
+        setClipChildren(enable);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index e733afc..0c385da 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -198,4 +198,11 @@
     public int getWrongPasswordStringId() {
         return R.string.kg_wrong_password;
     }
+
+    @Override
+    public void startAppearAnimation() {
+        // TODO: Fancy animation.
+        setAlpha(0);
+        animate().alpha(1).withLayer().setDuration(200);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 98122fc..5853ff9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -400,4 +400,11 @@
         KeyguardSecurityViewHelper.
                 hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
     }
+
+    @Override
+    public void startAppearAnimation() {
+        // TODO: Fancy animation.
+        setAlpha(0);
+        animate().alpha(1).withLayer().setDuration(200);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 94edc07..382cbec 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -81,6 +81,10 @@
         getSecurityView(mCurrentSecuritySelection).onPause();
     }
 
+    public void startAppearAnimation() {
+        getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
+    }
+
     void updateSecurityViews(boolean isBouncing) {
         int children = mSecurityViewFlipper.getChildCount();
         for (int i = 0; i < children; i++) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
index dfeacf3..86bd877 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
@@ -84,4 +84,9 @@
      * @param duration millisends for the transisiton animation.
      */
     void hideBouncer(int duration);
+
+    /**
+     * Starts the animation which should run when the security view appears.
+     */
+    void startAppearAnimation();
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 07239d1..178ca5e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -159,6 +159,14 @@
     }
 
     @Override
+    public void startAppearAnimation() {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.startAppearAnimation();
+        }
+    }
+
+    @Override
     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
         return p instanceof LayoutParams;
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
index 03e7b07..98baa04 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
@@ -244,4 +244,9 @@
         KeyguardSecurityViewHelper.
                 hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration);
     }
+
+    @Override
+    public void startAppearAnimation() {
+        // noop.
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index 4791956..09c4e7c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -135,6 +135,9 @@
         mPasswordEntry.requestFocus();
 
         mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
+        if (mEcaView instanceof EmergencyCarrierArea) {
+            ((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true);
+        }
     }
 
     @Override
@@ -270,5 +273,10 @@
             mCheckSimPinThread.start();
         }
     }
+
+    @Override
+    public void startAppearAnimation() {
+        // noop.
+    }
 }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
index b9c7f51..6215d34 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -186,6 +186,9 @@
         mPasswordEntry.requestFocus();
 
         mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
+        if (mEcaView instanceof EmergencyCarrierArea) {
+            ((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true);
+        }
     }
 
     @Override
@@ -339,6 +342,11 @@
     protected void verifyPasswordAndUnlock() {
         mStateMachine.next();
     }
+
+    @Override
+    public void startAppearAnimation() {
+        // noop.
+    }
 }
 
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
index 5d5168c..3f6ced6 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
@@ -39,7 +39,7 @@
 
     @Override
     public void cleanUp() {
-        // TODO Auto-generated method stub
+        getSecurityContainer().onPause();
     }
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index ae55c4a..bef94fa 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -95,6 +95,10 @@
         final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
         setEnableMarquee(screenOn);
         refresh();
+
+        // Disable elegant text height because our fancy colon makes the ymin value huge for no
+        // reason.
+        mClockView.setElegantTextHeight(false);
     }
 
     protected void refresh() {
@@ -164,6 +168,10 @@
 
             clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel);
 
+            // Use fancy colon.
+            clockView24 = clockView24.replace(':', '\uee01');
+            clockView12 = clockView12.replace(':', '\uee01');
+
             cacheKey = key;
         }
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index a9206e7..3e444fa 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -237,15 +237,17 @@
         if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
         mSecurityContainer.showPrimarySecurityScreen(false);
         mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
-
-        // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
-        // layout is blank but forcing a layout causes it to reappear (e.g. with with
-        // hierarchyviewer).
-        requestLayout();
         requestFocus();
     }
 
     /**
+     * Starts the animation when the Keyguard gets shown.
+     */
+    public void startAppearAnimation() {
+        mSecurityContainer.startAppearAnimation();
+    }
+
+    /**
      * Verify that the user can get past the keyguard securely.  This is called,
      * for example, when the phone disables the keyguard but then wants to launch
      * something else that requires secure access.
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index ba3c042..c89f9bf 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -60,7 +60,7 @@
   </plurals>
     <string name="cancel" msgid="4373674107267141885">"បោះបង់"</string>
     <string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើម​ឡើងវិញ"</string>
-    <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មាន​​​ការ​ភ្ជាប់​ទៅ​ម៉ាស៊ីន​បោះពុម្ព​"</string>
+    <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មាន​​​ការ​ភ្ជាប់​ទៅ​ម៉ាស៊ីន​បោះពុម្ព"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"មិន​ស្គាល់"</string>
     <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – មិន​អាច​ប្រើ​បាន"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"មិន​អាច​បង្កើត​ការ​ងារ​បោះពុម្ព"</string>
diff --git a/packages/SettingsProvider/res/values-af/defaults.xml b/packages/SettingsProvider/res/values-af/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-af/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-am/defaults.xml b/packages/SettingsProvider/res/values-am/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-am/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ar/defaults.xml b/packages/SettingsProvider/res/values-ar/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ar/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-bg/defaults.xml b/packages/SettingsProvider/res/values-bg/defaults.xml
new file mode 100644
index 0000000..1d546ff
--- /dev/null
+++ b/packages/SettingsProvider/res/values-bg/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s от %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ca/defaults.xml b/packages/SettingsProvider/res/values-ca/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ca/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-cs/defaults.xml b/packages/SettingsProvider/res/values-cs/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-cs/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-da/defaults.xml b/packages/SettingsProvider/res/values-da/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-da/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-de/defaults.xml b/packages/SettingsProvider/res/values-de/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-de/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-el/defaults.xml b/packages/SettingsProvider/res/values-el/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-el/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-en-rGB/defaults.xml b/packages/SettingsProvider/res/values-en-rGB/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-en-rGB/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-en-rIN/defaults.xml b/packages/SettingsProvider/res/values-en-rIN/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-en-rIN/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-es-rUS/defaults.xml b/packages/SettingsProvider/res/values-es-rUS/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-es-rUS/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-es/defaults.xml b/packages/SettingsProvider/res/values-es/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-es/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-et-rEE/defaults.xml b/packages/SettingsProvider/res/values-et-rEE/defaults.xml
new file mode 100644
index 0000000..5f99ed9
--- /dev/null
+++ b/packages/SettingsProvider/res/values-et-rEE/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s, %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-fa/defaults.xml b/packages/SettingsProvider/res/values-fa/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-fa/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-fi/defaults.xml b/packages/SettingsProvider/res/values-fi/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-fi/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-fr-rCA/defaults.xml b/packages/SettingsProvider/res/values-fr-rCA/defaults.xml
new file mode 100644
index 0000000..1a04b0f
--- /dev/null
+++ b/packages/SettingsProvider/res/values-fr-rCA/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s de %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-hi/defaults.xml b/packages/SettingsProvider/res/values-hi/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-hi/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-hr/defaults.xml b/packages/SettingsProvider/res/values-hr/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-hr/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-hu/defaults.xml b/packages/SettingsProvider/res/values-hu/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-hu/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-hy-rAM/defaults.xml b/packages/SettingsProvider/res/values-hy-rAM/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-hy-rAM/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-in/defaults.xml b/packages/SettingsProvider/res/values-in/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-in/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-it/defaults.xml b/packages/SettingsProvider/res/values-it/defaults.xml
new file mode 100644
index 0000000..bc995b0
--- /dev/null
+++ b/packages/SettingsProvider/res/values-it/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-iw/defaults.xml b/packages/SettingsProvider/res/values-iw/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-iw/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ja/defaults.xml b/packages/SettingsProvider/res/values-ja/defaults.xml
new file mode 100644
index 0000000..bc995b0
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ja/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ka-rGE/defaults.xml b/packages/SettingsProvider/res/values-ka-rGE/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ka-rGE/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-km-rKH/defaults.xml b/packages/SettingsProvider/res/values-km-rKH/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-km-rKH/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ko/defaults.xml b/packages/SettingsProvider/res/values-ko/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ko/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-lt/defaults.xml b/packages/SettingsProvider/res/values-lt/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-lt/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-lv/defaults.xml b/packages/SettingsProvider/res/values-lv/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-lv/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ms-rMY/defaults.xml b/packages/SettingsProvider/res/values-ms-rMY/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ms-rMY/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-nb/defaults.xml b/packages/SettingsProvider/res/values-nb/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-nb/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-nl/defaults.xml b/packages/SettingsProvider/res/values-nl/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-nl/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-pl/defaults.xml b/packages/SettingsProvider/res/values-pl/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-pl/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-pt-rPT/defaults.xml b/packages/SettingsProvider/res/values-pt-rPT/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-pt-rPT/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-pt/defaults.xml b/packages/SettingsProvider/res/values-pt/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-pt/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ro/defaults.xml b/packages/SettingsProvider/res/values-ro/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ro/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ru/defaults.xml b/packages/SettingsProvider/res/values-ru/defaults.xml
new file mode 100644
index 0000000..bc995b0
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ru/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-sk/defaults.xml b/packages/SettingsProvider/res/values-sk/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-sk/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-sl/defaults.xml b/packages/SettingsProvider/res/values-sl/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-sl/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-sr/defaults.xml b/packages/SettingsProvider/res/values-sr/defaults.xml
new file mode 100644
index 0000000..bc995b0
--- /dev/null
+++ b/packages/SettingsProvider/res/values-sr/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-sv/defaults.xml b/packages/SettingsProvider/res/values-sv/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-sv/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-sw/defaults.xml b/packages/SettingsProvider/res/values-sw/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-sw/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-th/defaults.xml b/packages/SettingsProvider/res/values-th/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-th/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-tl/defaults.xml b/packages/SettingsProvider/res/values-tl/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-tl/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-tr/defaults.xml b/packages/SettingsProvider/res/values-tr/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-tr/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-uk/defaults.xml b/packages/SettingsProvider/res/values-uk/defaults.xml
new file mode 100644
index 0000000..8ca4583
--- /dev/null
+++ b/packages/SettingsProvider/res/values-uk/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%2$s о %1$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-vi/defaults.xml b/packages/SettingsProvider/res/values-vi/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-vi/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rHK/defaults.xml b/packages/SettingsProvider/res/values-zh-rHK/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-zh-rHK/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rTW/defaults.xml b/packages/SettingsProvider/res/values-zh-rTW/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-zh-rTW/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-zu/defaults.xml b/packages/SettingsProvider/res/values-zu/defaults.xml
new file mode 100644
index 0000000..295b4f5
--- /dev/null
+++ b/packages/SettingsProvider/res/values-zu/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6b62c25..e9cb197 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -52,6 +52,8 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+
 
     <!-- Physical hardware -->
     <uses-permission android:name="android.permission.MANAGE_USB" />
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
deleted file mode 100644
index c779437..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png
deleted file mode 100644
index 18257e0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_highlight.png
deleted file mode 100644
index 8ddb375..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index 57a3b99..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/search_light.png b/packages/SystemUI/res/drawable-hdpi/search_light.png
deleted file mode 100644
index 3c0dc4e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/search_light.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/search_light_land.png b/packages/SystemUI/res/drawable-hdpi/search_light_land.png
deleted file mode 100644
index 731f19b5..0000000
--- a/packages/SystemUI/res/drawable-hdpi/search_light_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
deleted file mode 100644
index 98ba690..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png
deleted file mode 100644
index a35c30d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_highlight.png
deleted file mode 100644
index 71e1303..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index 1de0a3a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_light.png b/packages/SystemUI/res/drawable-mdpi/search_light.png
deleted file mode 100644
index 8010ce7..0000000
--- a/packages/SystemUI/res/drawable-mdpi/search_light.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_light_land.png b/packages/SystemUI/res/drawable-mdpi/search_light_land.png
deleted file mode 100644
index a4d82f0..0000000
--- a/packages/SystemUI/res/drawable-mdpi/search_light_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/heads_up_window_bg.9.png
deleted file mode 100644
index b30cf15..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/heads_up_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
deleted file mode 100644
index 8014b70..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index 41a34e2..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
deleted file mode 100644
index 9c623e5..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index a011aa1..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png
deleted file mode 100644
index 31eb8f7..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
deleted file mode 100644
index 61a36e3..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index 52bf290..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png
deleted file mode 100644
index c76d0e1..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png
deleted file mode 100644
index e5d4273..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index 1cc5009..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
deleted file mode 100644
index 61947ea..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_lock_open_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_lock_open_24dp.png
deleted file mode 100644
index 467d558..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_lock_open_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png
deleted file mode 100644
index d14a67f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_highlight.png
deleted file mode 100644
index c44aafc..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index 05da6da..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_light.png b/packages/SystemUI/res/drawable-xhdpi/search_light.png
deleted file mode 100644
index 6d46fdd..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/search_light.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_light_land.png b/packages/SystemUI/res/drawable-xhdpi/search_light_land.png
deleted file mode 100644
index b62c74e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/search_light_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
deleted file mode 100644
index 0b563b1..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png
deleted file mode 100644
index 07f16c3..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png
deleted file mode 100644
index 0df6203..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png
deleted file mode 100644
index b400b14..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_light.png b/packages/SystemUI/res/drawable-xxhdpi/search_light.png
deleted file mode 100644
index 7742207..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/search_light.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png b/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png
deleted file mode 100644
index f364577..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
deleted file mode 100644
index 3600ee6..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_open_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_open_24dp.png
deleted file mode 100644
index e7d2a9a..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_open_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
new file mode 100644
index 0000000..a7e8514
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_account_circle.xml
@@ -0,0 +1,28 @@
+<!--
+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" >
+    <size
+        android:width="24dp"
+        android:height="24dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_24dp.xml b/packages/SystemUI/res/drawable/ic_lock_24dp.xml
new file mode 100644
index 0000000..b2e486c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lock_24dp.xml
@@ -0,0 +1,28 @@
+<!--
+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" >
+    <size
+        android:width="24.0dp"
+        android:height="24.0dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="@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
new file mode 100644
index 0000000..28b16dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lock_open_24dp.xml
@@ -0,0 +1,28 @@
+<!--
+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" >
+    <size
+        android:width="24.0dp"
+        android:height="24.0dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="@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_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
index 3a20c58..787eec5 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -24,5 +24,5 @@
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.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.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.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z" />
+        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_audible.xml b/packages/SystemUI/res/drawable/ic_ringer_audible.xml
new file mode 100644
index 0000000..2969948
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_ringer_audible.xml
@@ -0,0 +1,28 @@
+<!--
+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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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_silent.xml b/packages/SystemUI/res/drawable/ic_ringer_silent.xml
new file mode 100644
index 0000000..b5837f6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_ringer_silent.xml
@@ -0,0 +1,28 @@
+<!--
+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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
new file mode 100644
index 0000000..d8ded58
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
@@ -0,0 +1,28 @@
+<!--
+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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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_vol_zen_off.xml b/packages/SystemUI/res/drawable/ic_vol_zen_off.xml
new file mode 100644
index 0000000..ea5ab70
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_vol_zen_off.xml
@@ -0,0 +1,30 @@
+<!--
+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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
+        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.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_vol_zen_on.xml b/packages/SystemUI/res/drawable/ic_vol_zen_on.xml
new file mode 100644
index 0000000..44024f3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_vol_zen_on.xml
@@ -0,0 +1,28 @@
+<!--
+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" >
+    <size
+        android:width="32dp"
+        android:height="32dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#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.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml
index 09d0d7d..5daec20 100644
--- a/packages/SystemUI/res/drawable/notification_header_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_header_bg.xml
@@ -19,13 +19,11 @@
     <item android:state_pressed="true">
         <shape>
             <solid android:color="@color/background_color_1_press" />
-            <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
         </shape>
     </item>
     <item>
         <shape>
             <solid android:color="@color/background_color_1" />
-            <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
         </shape>
     </item>
 </selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_panel_background.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml
index c324976..a1a5362 100644
--- a/packages/SystemUI/res/drawable/qs_panel_background.xml
+++ b/packages/SystemUI/res/drawable/qs_panel_background.xml
@@ -13,11 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-        android:insetLeft="@dimen/notification_side_padding"
-        android:insetRight="@dimen/notification_side_padding">
-    <shape>
-        <solid android:color="@color/system_primary_color" />
-        <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
-    </shape>
-</inset>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/system_primary_color" />
+    <corners
+        android:radius="@*android:dimen/notification_quantum_rounded_rect_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/ripple_drawable.xml b/packages/SystemUI/res/drawable/ripple_drawable.xml
new file mode 100644
index 0000000..d2bff42
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ripple_drawable.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
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:tint="?android:attr/colorControlHighlight"
+        android:tintMode="src_over"
+        android:pinned="true" />
diff --git a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
index 5f12706..a291495 100644
--- a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
@@ -55,7 +55,7 @@
                 systemui:keyCode="4"
                 android:layout_weight="0"
                 android:scaleType="center"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_back"
                 />
             <View 
@@ -71,7 +71,7 @@
                 systemui:keyCode="3"
                 systemui:keyRepeat="false"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_home"
                 />
             <View 
@@ -85,7 +85,7 @@
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_recent"
                 />
             <FrameLayout
@@ -99,7 +99,7 @@
                     android:contentDescription="@string/accessibility_menu"
                     android:src="@drawable/ic_sysbar_menu"
                     android:visibility="invisible"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    android:background="@drawable/ripple_drawable"
                     systemui:keyCode="82" />
                 <com.android.systemui.statusbar.policy.KeyButtonView
                     android:id="@+id/ime_switcher"
@@ -109,7 +109,7 @@
                     android:scaleType="centerInside"
                     android:src="@drawable/ic_ime_switcher_default"
                     android:visibility="invisible"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+                    android:background="@drawable/ripple_drawable" />
             </FrameLayout>
         </LinearLayout>
 
@@ -158,17 +158,6 @@
                 />
         </LinearLayout>
 
-        <com.android.systemui.statusbar.policy.KeyButtonView
-            android:layout_width="80dp"
-            android:id="@+id/search_light"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_horizontal"
-            android:src="@drawable/search_light"
-            android:scaleType="center"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_search_light"
-            />
-
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
@@ -212,7 +201,7 @@
                     android:layout_weight="0"
                     android:visibility="invisible"
                     android:contentDescription="@string/accessibility_menu"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
+                    android:background="@drawable/ripple_drawable" />
                 <com.android.systemui.statusbar.policy.KeyButtonView
                     android:id="@+id/ime_switcher"
                     android:layout_height="@dimen/navigation_extra_key_width"
@@ -221,7 +210,7 @@
                     android:scaleType="centerInside"
                     android:src="@drawable/ic_ime_switcher_default"
                     android:visibility="invisible"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+                    android:background="@drawable/ripple_drawable" />
             </FrameLayout>
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                 android:layout_height="80dp"
@@ -231,7 +220,7 @@
                 systemui:keyCode="4"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_back"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                android:background="@drawable/ripple_drawable"
                 />
             <View
                 android:layout_height="match_parent"
@@ -247,7 +236,7 @@
                 systemui:keyRepeat="false"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_home"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                android:background="@drawable/ripple_drawable"
                 />
             <View 
                 android:layout_height="match_parent"
@@ -261,7 +250,7 @@
                 android:src="@drawable/ic_sysbar_recent_land"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_recent"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                android:background="@drawable/ripple_drawable"
                 />
             <View
                 android:layout_height="40dp"
@@ -316,17 +305,6 @@
                 />
         </LinearLayout>
 
-        <com.android.systemui.statusbar.policy.KeyButtonView
-            android:id="@+id/search_light"
-            android:layout_height="80dp"
-            android:layout_width="match_parent"
-            android:layout_gravity="center_vertical"
-            android:src="@drawable/search_light"
-            android:scaleType="center"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_search_light"
-            />
-
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
deleted file mode 100644
index f7035fe..0000000
--- a/packages/SystemUI/res/layout-sw600dp/heads_up.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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.policy.HeadsUpNotificationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    >
-    <FrameLayout
-        android:id="@+id/content_holder"
-        android:layout_height="wrap_content"
-        android:layout_width="@dimen/notification_panel_width"
-        android:background="@drawable/heads_up_window_bg"
-        />
-</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 6a2e3c6..f8b7bae 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -59,7 +59,7 @@
                 android:src="@drawable/ic_sysbar_back"
                 systemui:keyCode="4"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_back"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
@@ -69,7 +69,7 @@
                 systemui:keyCode="3"
                 systemui:keyRepeat="true"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_home"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
@@ -77,7 +77,7 @@
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_recent"
                 />
             <Space 
@@ -98,7 +98,7 @@
                     systemui:keyCode="82"
                     android:visibility="invisible"
                     android:contentDescription="@string/accessibility_menu"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    android:background="@drawable/ripple_drawable"
                     />
                 <com.android.systemui.statusbar.policy.KeyButtonView
                     android:id="@+id/ime_switcher"
@@ -109,7 +109,7 @@
                     android:src="@drawable/ic_ime_switcher_default"
                     android:visibility="invisible"
                     android:contentDescription="@string/accessibility_ime_switch_button"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+                    android:background="@drawable/ripple_drawable" />
             </FrameLayout>
         </LinearLayout>
 
@@ -156,17 +156,6 @@
                 />
         </LinearLayout>
 
-        <com.android.systemui.statusbar.policy.KeyButtonView
-            android:layout_width="128dp"
-            android:id="@+id/search_light"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_horizontal"
-            android:src="@drawable/search_light"
-            android:scaleType="center"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_search_light"
-            />
-
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
@@ -216,7 +205,7 @@
                 android:src="@drawable/ic_sysbar_back"
                 systemui:keyCode="4"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_back"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
@@ -226,7 +215,7 @@
                 systemui:keyCode="3"
                 systemui:keyRepeat="true"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_home"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
@@ -234,7 +223,7 @@
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_recent"
                 />
             <Space 
@@ -255,7 +244,7 @@
                     systemui:keyCode="82"
                     android:visibility="invisible"
                     android:contentDescription="@string/accessibility_menu"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    android:background="@drawable/ripple_drawable"
                     />
                 <com.android.systemui.statusbar.policy.KeyButtonView
                     android:id="@+id/ime_switcher"
@@ -266,7 +255,7 @@
                     android:visibility="invisible"
                     android:contentDescription="@string/accessibility_ime_switch_button"
                     android:scaleType="centerInside"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+                    android:background="@drawable/ripple_drawable" />
             </FrameLayout>
         </LinearLayout>
 
@@ -313,17 +302,6 @@
                 />
         </LinearLayout>
 
-        <com.android.systemui.statusbar.policy.KeyButtonView
-            android:layout_width="162dp"
-            android:id="@+id/search_light"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_horizontal"
-            android:src="@drawable/search_light"
-            android:scaleType="center"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_search_light"
-            />
-
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 7d9cfa1..236fdc3 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -1,26 +1,30 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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.
-*/
+     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.
 -->
 <com.android.systemui.statusbar.policy.HeadsUpNotificationView
         xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:id="@+id/content_holder"
-        android:background="@drawable/notification_panel_bg"
-        />
\ No newline at end of file
+        android:layout_height="match_parent"
+        android:layout_width="match_parent">
+
+        <FrameLayout
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/notification_side_padding"
+                android:layout_marginEnd="@dimen/notification_side_padding"
+                android:elevation="16dp"
+                android:id="@+id/content_holder"
+                style="@style/NotificationsQuickSettings" />
+
+</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 2ec3766..9bf42b2 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -22,7 +22,7 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     >
-    <com.android.systemui.statusbar.phone.SwipeAffordanceView
+    <com.android.systemui.statusbar.AlphaImageView
         android:id="@+id/camera_button"
         android:layout_height="64dp"
         android:layout_width="64dp"
@@ -30,11 +30,9 @@
         android:tint="#ffffffff"
         android:src="@drawable/ic_camera_alt_24dp"
         android:scaleType="center"
-        android:contentDescription="@string/accessibility_camera_button"
-        systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
-        systemui:swipeDirection="start"/>
+        android:contentDescription="@string/accessibility_camera_button" />
 
-    <com.android.systemui.statusbar.phone.SwipeAffordanceView
+    <com.android.systemui.statusbar.AlphaImageView
         android:id="@+id/phone_button"
         android:layout_height="64dp"
         android:layout_width="64dp"
@@ -42,9 +40,7 @@
         android:tint="#ffffffff"
         android:src="@drawable/ic_phone_24dp"
         android:scaleType="center"
-        android:contentDescription="@string/accessibility_phone_button"
-        systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
-        systemui:swipeDirection="end"/>
+        android:contentDescription="@string/accessibility_phone_button" />
 
     <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
         android:id="@+id/keyguard_indication_text"
@@ -53,17 +49,16 @@
         android:layout_marginBottom="100dp"
         android:layout_gravity="bottom|center_horizontal"
         android:textStyle="italic"
-        android:textAppearance="?android:attr/textAppearanceMedium"/>
+        android:textColor="#ffffff"
+        android:textAppearance="?android:attr/textAppearanceSmall"/>
 
-    <ImageView
+    <com.android.systemui.statusbar.AlphaImageView
         android:id="@+id/lock_icon"
         android:layout_width="64dp"
         android:layout_height="64dp"
         android:layout_gravity="bottom|center_horizontal"
         android:src="@drawable/ic_lock_24dp"
         android:scaleType="center"
-        android:alpha="0.7"
-        android:layerType="hardware"
-        android:tint="#ffffffff"/>
+        android:tint="#ffffffff" />
 
-</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
\ No newline at end of file
+</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 7470409..7616cb1 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -55,7 +55,7 @@
                 systemui:keyCode="4"
                 android:layout_weight="0"
                 android:scaleType="center"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_back"
                 />
             <View 
@@ -71,7 +71,7 @@
                 systemui:keyCode="3"
                 systemui:keyRepeat="false"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_home"
                 />
             <View 
@@ -85,7 +85,7 @@
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
                 android:layout_weight="0"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                android:background="@drawable/ripple_drawable"
                 android:contentDescription="@string/accessibility_recent"
                 />
             <FrameLayout
@@ -99,7 +99,7 @@
                     android:contentDescription="@string/accessibility_menu"
                     android:src="@drawable/ic_sysbar_menu"
                     android:visibility="invisible"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    android:background="@drawable/ripple_drawable"
                     systemui:keyCode="82" />
 
                 <com.android.systemui.statusbar.policy.KeyButtonView
@@ -110,7 +110,7 @@
                     android:scaleType="centerInside"
                     android:src="@drawable/ic_ime_switcher_default"
                     android:visibility="invisible"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+                    android:background="@drawable/ripple_drawable" />
             </FrameLayout>
 
         </LinearLayout>
@@ -160,22 +160,6 @@
                 />
         </LinearLayout>
 
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-
-            <com.android.systemui.statusbar.policy.KeyButtonView
-                android:layout_width="80dp"
-                android:id="@+id/search_light"
-                android:layout_height="match_parent"
-                android:layout_gravity="center"
-                android:src="@drawable/search_light"
-                android:scaleType="center"
-                android:visibility="gone"
-                android:contentDescription="@string/accessibility_search_light"
-                />
-        </FrameLayout>
-
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
@@ -219,7 +203,7 @@
                     android:scaleType="centerInside"
                     android:src="@drawable/ic_ime_switcher_default"
                     android:visibility="invisible"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+                    android:background="@drawable/ripple_drawable" />
 
                 <com.android.systemui.statusbar.policy.KeyButtonView
                     android:id="@+id/menu"
@@ -228,7 +212,7 @@
                     android:contentDescription="@string/accessibility_menu"
                     android:src="@drawable/ic_sysbar_menu_land"
                     android:visibility="invisible"
-                    systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                    android:background="@drawable/ripple_drawable"
                     systemui:keyCode="82" />
             </FrameLayout>
 
@@ -238,7 +222,7 @@
                 android:src="@drawable/ic_sysbar_recent_land"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_recent"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                android:background="@drawable/ripple_drawable"
                 />
             <View 
                 android:layout_height="match_parent"
@@ -254,7 +238,7 @@
                 systemui:keyRepeat="false"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_home"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                android:background="@drawable/ripple_drawable"
                 />
             <View 
                 android:layout_height="match_parent"
@@ -270,7 +254,7 @@
                 systemui:keyCode="4"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_back"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                android:background="@drawable/ripple_drawable"
                 />
             <View
                 android:layout_height="40dp"
@@ -325,19 +309,6 @@
                 />
         </LinearLayout>
 
-        <com.android.systemui.statusbar.policy.KeyButtonView
-            android:id="@+id/search_light"
-            android:layout_height="80dp"
-            android:layout_width="match_parent"
-            android:layout_gravity="center_vertical"
-            android:src="@drawable/search_light_land"
-            android:scaleType="center"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_search_light"
-            />
-
-        <!-- No camera button in landscape mode -->
-
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
new file mode 100644
index 0000000..e73b431
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/system_primary_color" >
+
+    <ImageView
+        android:id="@android:id/button1"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentStart="true"
+        android:contentDescription="@string/accessibility_quick_settings_close"
+        android:padding="@dimen/qs_panel_padding"
+        android:src="@drawable/ic_qs_close" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:layout_alignParentTop="true"
+        android:layout_toEndOf="@android:id/button1"
+        android:layout_toStartOf="@android:id/checkbox"
+        android:gravity="center_vertical"
+        android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+
+    <ImageView
+        android:id="@android:id/custom"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@android:id/title"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
+        android:scaleType="fitXY"
+        android:src="?android:attr/dividerHorizontal" />
+
+    <FrameLayout
+        android:id="@android:id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@android:id/custom" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 85de645..398787f 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -16,11 +16,10 @@
 <FrameLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/quick_settings_container"
-        android:paddingLeft="@dimen/notification_side_padding"
-        android:paddingRight="@dimen/notification_side_padding"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@drawable/qs_panel_background" >
+        android:background="@drawable/qs_panel_background"
+        android:elevation="2dp">
     <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
             android:background="#0000"
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
deleted file mode 100644
index 85b294d..0000000
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?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.
--->
-<com.android.systemui.qs.tiles.ZenModeDetail xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@color/system_secondary_color" >
-
-    <ImageView
-        android:id="@android:id/button1"
-        android:src="@drawable/ic_qs_close"
-        android:layout_width="64dp"
-        android:layout_height="64dp"
-        android:layout_alignParentStart="true"
-        android:padding="@dimen/qs_panel_padding" />
-
-    <Switch
-        android:id="@android:id/checkbox"
-        android:layout_width="wrap_content"
-        android:layout_height="64dp"
-        android:layout_alignParentEnd="true"
-        android:gravity="center"
-        android:padding="@dimen/qs_panel_padding" />
-
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="match_parent"
-        android:layout_height="64dp"
-        android:layout_toEndOf="@android:id/button1"
-        android:layout_toStartOf="@android:id/checkbox"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-        android:gravity="center_vertical"
-        android:paddingStart="@dimen/qs_panel_padding"
-        android:text="@string/zen_mode_title" />
-
-    <View
-        android:id="@android:id/custom"
-        android:layout_width="match_parent"
-        android:layout_height="2dp"
-        android:layout_below="@android:id/title"
-        android:background="#888" />
-
-    <ListView
-        android:id="@android:id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_above="@android:id/button2"
-        android:layout_below="@android:id/custom"
-        android:divider="#00000000"
-        android:dividerHeight="0px" />
-
-    <TextView
-        android:id="@android:id/button2"
-        style="@style/QSBorderless"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentEnd="true"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-        android:padding="@dimen/qs_panel_padding"
-        android:text="@string/quick_settings_more_settings"
-        android:textAllCaps="true" />
-
-</com.android.systemui.qs.tiles.ZenModeDetail>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
deleted file mode 100644
index fd27aaf..0000000
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
-
-    <RadioButton
-        android:id="@android:id/checkbox"
-        android:layout_width="32dp"
-        android:layout_height="64dp"
-        android:layout_alignParentStart="true"
-        android:layout_marginStart="@dimen/qs_panel_padding"
-        android:gravity="center" />
-
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="match_parent"
-        android:layout_height="64dp"
-        android:layout_toEndOf="@android:id/checkbox"
-        android:layout_toStartOf="@android:id/button1"
-        android:ellipsize="end"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-        android:gravity="center_vertical"
-        android:maxLines="1"
-        android:text="@string/accessibility_back" />
-
-    <ImageView
-        android:id="@android:id/button1"
-        android:src="@drawable/ic_qs_minus"
-        android:layout_width="64dp"
-        android:layout_height="64dp"
-        android:layout_alignParentEnd="true"
-        android:layout_marginEnd="48dp"
-        android:padding="@dimen/qs_panel_padding"
-        android:paddingRight="0px" />
-
-    <ImageView
-        android:id="@android:id/button2"
-        android:src="@drawable/ic_qs_plus"
-        android:layout_width="64dp"
-        android:layout_height="64dp"
-        android:layout_alignParentEnd="true"
-        android:padding="@dimen/qs_panel_padding" />
-
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 1efda8c..97ed9a0 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -15,7 +15,8 @@
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    style="@style/BrightnessDialogContainer">
+    style="@style/BrightnessDialogContainer"
+    android:clickable="true">
 
     <ImageView
         android:id="@+id/brightness_icon"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 2ec9935..cde83bf 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -59,8 +59,8 @@
             android:id="@+id/scroll_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:visibility="invisible"
             android:scrollbars="none"
+            android:overScrollMode="never"
             android:fillViewport="true">
             <LinearLayout
                 android:layout_width="match_parent"
@@ -70,7 +70,9 @@
                     layout="@layout/qs_panel"
                     android:layout_marginTop="@dimen/status_bar_header_height_expanded"
                     android:layout_width="match_parent"
-                    android:layout_height="wrap_content"/>
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="@dimen/notification_side_padding"
+                    android:layout_marginRight="@dimen/notification_side_padding"/>
 
                 <!-- A view to reserve space for the collapsed stack -->
                 <View
@@ -79,7 +81,6 @@
             </LinearLayout>
         </com.android.systemui.statusbar.phone.ObservableScrollView>
 
-
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
             android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 89fa988..7f34041 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -25,7 +25,7 @@
     android:paddingStart="@dimen/notification_side_padding"
     android:paddingEnd="@dimen/notification_side_padding"
     android:baselineAligned="false"
-    android:elevation="10dp"
+    android:elevation="4dp"
     >
 
     <View
@@ -65,22 +65,13 @@
             />
     </RelativeLayout>
 
-    <com.android.keyguard.CarrierText
-        android:id="@+id/keyguard_carrier_text"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/status_bar_header_height_keyguard"
-        android:layout_marginLeft="8dp"
-        android:gravity="center_vertical"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
     <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
         android:layout_width="40dp"
         android:layout_height="@dimen/status_bar_header_height"
         android:layout_alignParentEnd="true"
         android:background="@null"
         android:scaleType="centerInside"
-        android:padding="6dp"
+        android:padding="8dp"
         />
 
     <ImageButton android:id="@+id/settings_button"
@@ -98,6 +89,18 @@
         android:layout_marginEnd="4dp"
         />
 
+    <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="8dp"
+        android:layout_toStartOf="@id/system_icons_container"
+        android:gravity="center_vertical"
+        android:ellipsize="marquee"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="#ffffff"
+        android:singleLine="true" />
+
     <include
         layout="@layout/quick_settings_brightness_dialog"
         android:id="@+id/brightness_container"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 26616cd..e84300d 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -26,6 +26,10 @@
     android:fitsSystemWindows="true"
     android:descendantFocusability="afterDescendants">
 
+    <View android:id="@+id/scrim_behind"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
     <include layout="@layout/status_bar"
         android:layout_width="match_parent"
         android:layout_height="@dimen/status_bar_height" />
@@ -40,4 +44,8 @@
             android:visibility="gone" />
     </com.android.systemui.statusbar.phone.PanelHolder>
 
+    <View android:id="@+id/scrim_in_front"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/user_switcher_host.xml b/packages/SystemUI/res/layout/user_switcher_host.xml
index 70c5042..816af57 100644
--- a/packages/SystemUI/res/layout/user_switcher_host.xml
+++ b/packages/SystemUI/res/layout/user_switcher_host.xml
@@ -27,7 +27,7 @@
     <FrameLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="@*android:dimen/volume_panel_top"
+            android:layout_marginTop="@dimen/volume_panel_top"
             android:background="@*android:drawable/dialog_full_holo_dark">
         <ListView android:id="@android:id/list"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/volume_panel.xml b/packages/SystemUI/res/layout/volume_panel.xml
new file mode 100644
index 0000000..bc7288d
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_panel.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/visible_panel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal" >
+
+    <FrameLayout
+        android:id="@+id/slider_panel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_toLeftOf="@+id/expand_button_divider" />
+
+    <ImageView
+        android:id="@+id/expand_button_divider"
+        android:layout_width="wrap_content"
+        android:layout_height="32dip"
+        android:layout_gravity="top"
+        android:layout_marginBottom="16dip"
+        android:layout_marginTop="16dip"
+        android:layout_toLeftOf="@+id/expand_button"
+        android:scaleType="fitXY"
+        android:src="?android:attr/dividerVertical" />
+
+    <ImageView
+        android:id="@+id/expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_gravity="top"
+        style="@style/BorderlessButton.Tiny"
+        android:padding="16dip" />
+
+    <ImageView
+        android:id="@+id/zen_panel_divider"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/slider_panel"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
+        android:scaleType="fitXY"
+        android:src="?android:attr/dividerHorizontal" />
+
+    <ViewStub
+        android:id="@+id/zen_panel_stub"
+        android:layout_below="@+id/zen_panel_divider"
+        android:inflatedId="@+id/zen_panel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout="@layout/zen_mode_panel" />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/volume_panel_item.xml b/packages/SystemUI/res/layout/volume_panel_item.xml
new file mode 100644
index 0000000..98cb8f4
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_panel_item.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="80dip"
+    android:orientation="horizontal"
+    android:layout_marginTop="8dip"
+    android:layout_marginBottom="8dip"
+    android:gravity="start|center_vertical">
+
+    <ImageView
+        android:id="@+id/stream_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dip"
+        android:background="?android:attr/selectableItemBackground"
+        android:contentDescription="@null" />
+
+    <SeekBar
+        style="?android:attr/seekBarStyle"
+        android:id="@+id/seekbar"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:padding="16dip"
+        android:layout_marginEnd="16dip" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml
new file mode 100644
index 0000000..8b344000
--- /dev/null
+++ b/packages/SystemUI/res/layout/zen_mode_condition.xml
@@ -0,0 +1,62 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" >
+
+    <RadioButton
+        android:id="@android:id/checkbox"
+        android:layout_width="32dp"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_alignParentStart="true"
+        android:gravity="center" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_toEndOf="@android:id/checkbox"
+        android:layout_toStartOf="@android:id/button1"
+        android:ellipsize="end"
+        android:gravity="center_vertical"
+        android:maxLines="1"
+        android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
+
+    <ImageView
+        android:id="@android:id/button1"
+        style="@style/BorderlessButton"
+        android:layout_width="@dimen/zen_mode_condition_height"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"
+        android:layout_marginEnd="@dimen/zen_mode_condition_height"
+        android:contentDescription="@string/accessibility_quick_settings_less_time"
+        android:padding="@dimen/zen_mode_condition_detail_button_padding"
+        android:src="@drawable/ic_qs_minus" />
+
+    <ImageView
+        android:id="@android:id/button2"
+        style="@style/BorderlessButton"
+        android:layout_width="@dimen/zen_mode_condition_height"
+        android:layout_height="@dimen/zen_mode_condition_height"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"
+        android:contentDescription="@string/accessibility_quick_settings_more_time"
+        android:padding="@dimen/zen_mode_condition_detail_button_padding"
+        android:src="@drawable/ic_qs_plus" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
new file mode 100644
index 0000000..ae04bf5
--- /dev/null
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+<!-- extends LinearLayout -->
+<com.android.systemui.volume.ZenModePanel xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/zen_mode_panel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/system_primary_color"
+    android:orientation="vertical"
+    android:padding="@dimen/qs_panel_padding" >
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_marginBottom="8dp"
+        android:text="@string/zen_mode_title"
+        android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+
+    <LinearLayout
+        android:id="@android:id/content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" />
+
+    <TextView
+        android:id="@android:id/button2"
+        style="@style/BorderlessButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_gravity="end"
+        android:text="@string/quick_settings_more_settings"
+        android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+
+</com.android.systemui.volume.ZenModePanel>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index e43464c..c45254e 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Ligging <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Wekker gestel vir <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Maak paneel toe"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Meer tyd"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Minder tyd"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G-data gedeaktiveer"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G data gedeaktiveer"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobieldata gedeaktiveer"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellings"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"USB-verbinding"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Warmkol"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Kennisgewings"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"ONLANGS"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Minder dringende kennisgewings hieronder"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tik weer om oop te maak"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Sleep op om te ontsluit"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat jy dit afskakel"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Een minuut lank"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d minute lank"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Een uur lank"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d uur lank"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ce3d14b..5c4d98b 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"ብሉቱዝ <xliff:g id="STATE">%s</xliff:g>።"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"አካባቢ <xliff:g id="STATE">%s</xliff:g>።"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"ማንቂያ ለ<xliff:g id="TIME">%s</xliff:g> ተዋቅሯል።"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G ውሂብ ቦዝኗል"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G ውሂብ ቦዝኗል"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"የተንቀሳቃሽ ውሂብ ቦዝኗል"</string>
@@ -207,6 +213,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ተጨማሪ ቅንብሮች"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"በማገናኘት ላይ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"መገናኛ ነጥብ"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"የቅርብ ጊዜዎች"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
@@ -226,4 +234,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"በጣም አስቸካይ ያልሆኑ ማሳወቂያዎች ከታች"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ለመክፈት ዳግም መታ ያድርጉ"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ለማስከፈት ወደ ላይ ያንሸራትቱ"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c9ddc23..d7c5651 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"البلوتوث <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"حالة الموقع: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"تم ضبط المنبه على <xliff:g id="TIME">%s</xliff:g>."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"تم تعطيل بيانات شبكات الجيل الثاني والجيل الثالث"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"تم تعطيل بيانات شبكة الجيل الرابع"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"تم تعطيل بيانات الجوال"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"المزيد من الإعدادات"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"النطاق"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"نقطة اتصال"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"الإشعارات"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"الأخيرة"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"الإشعارات الأقل إلحاحًا أدناه"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"انقر مرة أخرى للفتح"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"مرر سريعًا لأعلى لإلغاء القفل"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"لحين تعطيل هذا الإعداد"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"لمدة دقيقة واحدة"</item>
+    <item quantity="other" msgid="6924190729213550991">"‏لمدة %d من الدقائق"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"لمدة ساعة واحدة"</item>
+    <item quantity="other" msgid="5408537517529822157">"‏لمدة %d من الساعات"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index d396b8c..2405804 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Местоположението е <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Будилникът е навит за <xliff:g id="TIME">%s</xliff:g>."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G данните са деактивирани"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G данните са деактивирани"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобилните данни са деактивирани"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Още настройки"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Тетъринг"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка за достъп"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Известия"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"СКОРОШНИ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Ппоказване на по-малко спешните известия по-долу"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Докоснете отново, за да отворите"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Прекарайте пръст нагоре, за да отключите"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Докато не изключите това"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"За една минута"</item>
+    <item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"За един час"</item>
+    <item quantity="other" msgid="5408537517529822157">"За %d часа"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 51790b5..982e0c6 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Ubicació: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarma establerta a les <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Tanca el tauler."</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Més temps"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Menys temps"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Dades 2G-3G desactivades"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dades 4G desactivades"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dades mòbils desactivades"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Més opcions"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ancoratge a xarxa"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificacions"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificacions menys urgents a continuació"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Torna a tocar per obrir-la."</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Fes lliscar el dit cap amunt per desbloquejar el teclat."</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Fins que no ho desactivis"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Durant un minut"</item>
+    <item quantity="other" msgid="6924190729213550991">"Durant %d minuts"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Durant una hora"</item>
+    <item quantity="other" msgid="5408537517529822157">"Durant %d hores"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 91b8f6e..570e1bb 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Poloha: <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Budík je nastaven na <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Zavřít panel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Delší doba"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Kratší doba"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Datové přenosy 2G a 3G jsou zakázány"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datové přenosy 4G jsou zakázány"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilní data jsou zakázána"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Další nastavení"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Sdílení datového připojení"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Oznámení"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"POSLEDNÍ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Méně urgentní oznámení níže"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Oznámení otevřete opětovným klepnutím"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zařízení odemknete přejetím prstem nahoru"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokud tuto funkci nevypnete"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Na jednu minutu"</item>
+    <item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Na jednu hodinu"</item>
+    <item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1d1ca0a..127192a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Placering <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarmen er indstillet til <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Luk panelet"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Mere tid"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Mindre tid"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G-data er deaktiveret"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-data er deaktiveret"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobildata er deaktiveret"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere indstillinger"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Underretninger"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"SENESTE"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende underretninger nedenfor"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg for at låse op"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"I ét minut"</item>
+    <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"I én time"</item>
+    <item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a79193d..c9c7b8e 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Standort <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Wecker gestellt für <xliff:g id="TIME">%s</xliff:g>"</string>
+    <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="5257833881698644687">"2G-/3G-Daten deaktiviert"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-Daten deaktiviert"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilfunk Daten deaktiviert"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Weitere Einstellungen"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Benachrichtigungen"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"Letzte"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Weniger dringende Benachrichtigungen unten"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Erneut tippen, um Benachrichtigung zu öffnen"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zum Entsperren nach oben wischen"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Bis zur Deaktivierung"</string>
+  <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>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Für eine Stunde"</item>
+    <item quantity="other" msgid="5408537517529822157">"Für %d Stunden"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 32b7090..1d90dae 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Τοποθεσία <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Το ξυπνητήρι έχει οριστεί στις <xliff:g id="TIME">%s</xliff:g>."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Τα δεδομένα 2G-3G απενεργοποιήθηκαν"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Τα δεδομένα 4G απενεργοποιήθηκαν"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Τα δεδομένα κινητής τηλεφωνίας απενεργοποιήθηκαν"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Περισσότερες ρυθμίσεις"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Πρόσδεση"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Σημείο πρόσβασης Wi-Fi"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Ειδοποιήσεις"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"ΠΡΟΣΦΑΤΑ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Λιγότερο επείγουσες ειδοποιήσεις παρακάτω"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Πατήστε ξανά για να ανοίξετε"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Σύρετε για να ξεκλειδώσετε"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Μέχρι να το απενεργοποιήσετε"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Για ένα λεπτό"</item>
+    <item quantity="other" msgid="6924190729213550991">"Για %d λεπτά"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Για μία ώρα"</item>
+    <item quantity="other" msgid="5408537517529822157">"Για %d ώρες"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d26cfae..a9c6678 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Location <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm set for <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Close panel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"More time"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Less time"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G data disabled"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G data disabled"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobile data disabled"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
+    <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"For one hour"</item>
+    <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d48e627..a9c6678 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Location <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm set for <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Close panel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"More time"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Less time"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G data disabled"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G data disabled"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobile data disabled"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
@@ -223,8 +227,16 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d more"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
+    <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"For one hour"</item>
+    <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 23bcea28..6ca4ebc 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Ubicación <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarma: <xliff:g id="TIME">%s</xliff:g>"</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Cerrar panel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Más tiempo"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Menos tiempo"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Datos de 2G-3G inhabilitados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datos de 4G inhabilitados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Se inhabilitaron los datos móviles"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Más configuraciones"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificaciones"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
@@ -225,8 +229,16 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d más"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificaciones menos urgentes abajo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Presionar de nuevo para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar el dedo hacia arriba para desbloquear"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta que lo desactives"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
+    <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Durante una hora"</item>
+    <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3bded8b..d0e9c0a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Ubicación <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"La alarma sonará a la(s) <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Cerrar panel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Más tiempo"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Menos tiempo"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Datos 2G-3G inhabilitados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datos 4G inhabilitados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Datos móviles inhabilitados"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Más opciones"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificaciones"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificaciones menos urgente abajo"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Toca de nuevo para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta apagar el dispositivo"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
+    <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Durante una hora"</item>
+    <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 1979c55..c692b28 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Asukoht: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Määratud äratus: <xliff:g id="TIME">%s</xliff:g>"</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Sule paneel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Rohkem aega"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Vähem aega"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G–3G andmeside keelatud"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G andmeside keelatud"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobiilne andmeside keelatud"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Rohkem seadeid"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jagamine"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Leviala"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Märguanded"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"HILJUTISED"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
@@ -224,4 +228,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Vähem kiireloomulised märguanded on allpool"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Avamiseks puudutage uuesti"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Lukustuse tühistamiseks pühkige üles"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kuni lülitate selle välja"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Üheks minutiks"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d minutiks"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Üheks tunniks"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d tunniks"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 399740a..ee2c48d 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"بلوتوث <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"مکان <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"هشدار برای <xliff:g id="TIME">%s</xliff:g> تنظیم شد."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"‏داده 2G-3G غیرفعال شد"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"‏داده 4G غیر فعال شد"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"داده‌های تلفن همراه غیرفعال است"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"تنظیمات بیشتر"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"اتصال به اینترنت با تلفن همراه"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"نقطه اتصال"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"اعلان‌ها"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"موارد اخیر"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"اعلان‌های کمتر فوری در زیر"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"برای باز کردن دوباره ضربه بزنید"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"برای باز کردن قفل سریع به بالا بکشید"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"تا وقتی آن را خاموش کنید"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"برای یک دقیقه"</item>
+    <item quantity="other" msgid="6924190729213550991">"‏برای %d دقیقه"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"برای یک ساعت"</item>
+    <item quantity="other" msgid="5408537517529822157">"‏برای %d ساعت"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index be7eb9b..44d35b3 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Sijainti <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Hälytys asetettu, aika: <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Sulje paneeli"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Lisää aikaa"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Vähennä aikaa"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G-tiedonsiirto pois käytöstä"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-tiedonsiirto pois käytöstä"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobiilitiedonsiirto pois käytöstä"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Lisäasetukset"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jaettu yhteys"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Ilmoitukset"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"VIIMEISIMMÄT"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Vähemmän kiireelliset ilmoitukset ovat alla"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Avaa napauttamalla uudelleen"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Avaa lukitus pyyhkäisemällä ylös"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kunnes poistat tämän käytöstä"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Minuutiksi"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d minuutiksi"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Tunniksi"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d tunniksi"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 390ec81..d9790f6 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -158,6 +158,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth : <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Localisation <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarme réglée sur <xliff:g id="TIME">%s</xliff:g>"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Données 2G-3G  désactivées"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Données 4G désactivées"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Données mobiles désactivées"</string>
@@ -209,6 +215,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès sans fil"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
@@ -228,4 +236,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notifications moins urgentes affichées ci-dessous"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Touchez à nouveau pour ouvrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Glissez vers le haut pour déverrouiller"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a0c5cfe..d95fe06 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -158,6 +158,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth : <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Localisation <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarme réglée sur <xliff:g id="TIME">%s</xliff:g>"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Données 2G-3G désactivées"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Données 4G désactivées"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Données mobiles désactivées"</string>
@@ -209,6 +215,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informations sur l\'application"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
@@ -228,4 +236,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notifications moins urgentes ci-dessous"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Appuyer à nouveau pour ouvrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Faire glisser pour déverrouiller"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 6850b3d..60d7de1 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"स्थान <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"<xliff:g id="TIME">%s</xliff:g> के लिए अलार्म सेट किया गया."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G डेटा अक्षम"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G डेटा अक्षम"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"मोबाइल डेटा अक्षम"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"और सेटिंग"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"सूचनाएं"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"हाल ही का"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्‍लिकेशन जानकारी"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"कम अत्यावश्यक सूचनाएं नीचे दी गई हैं"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए पुन: टैप करें"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"जब तक आप इसे बंद नहीं कर देते"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"एक मिनट के लिए"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d मिनट के लिए"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"एक घंटे के लिए"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d घंटे के लिए"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b00c382..09dde42 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth – <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Lokacija <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Vrijeme alarma: <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Zatvori ploču"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Više vremena"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Manje vremena"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Onemogućeni su 2G-3G podaci"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Onemogućeni su 4G podaci"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Onemogućeni su mobilni podaci"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Više  postavki"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Dijeljenje veze"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Žarišna točka"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavijesti"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNO"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Manje hitne obavijesti pri dnu"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite opet za otvaranje"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Prijeđite prstom prema gore za otključavanje"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d min"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Jedan sat"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d h"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index b75c7f3..dc85416 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Helyadatok: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Ébresztés időpontja: <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Panel bezárása"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Több idő"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Kevesebb idő"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G adatforgalom letiltva"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G adatforgalom letiltva"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobil adatforgalom letiltva"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"További beállítások"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Megosztás"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Értesítések"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"LEGUTÓBBIAK"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"A kevésbé sürgős értesítések lentebb vannak"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Koppintson rá ismét a megnyitáshoz"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Húzza felfelé az ujját a feloldáshoz"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Amíg ki nem kapcsolja ezt"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Egy percen át"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d percen át"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Egy órán át"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d órán át"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 904b998..b11a004 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth-ը <xliff:g id="STATE">%s</xliff:g> է:"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Տեղադրությունը՝ <xliff:g id="STATE">%s</xliff:g>:"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Զարթուցիչը դրված է <xliff:g id="TIME">%s</xliff:g>-ին:"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G տվյալները անջատված են"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G տվյալները անջատված են"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Շարժական տվյալները անջատված են"</string>
@@ -207,6 +213,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Հավելյալ կարգավորումներ"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Միացում"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Թեժ կետ"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"ՎԵՐՋԻՆՆԵՐԸ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
@@ -226,4 +234,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Պակաս հրատապ ծանուցումները ստորև"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Կրկին հպեք՝ բացելու համար"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Սահեցրեք վերև` ապակողպելու համար"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 02313b37..f62209f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Lokasi <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm disetel ke <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Tutup panel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Lebih lama"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Lebih cepat"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Data 2G-3G dinonaktifkan"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data 4G dinonaktifkan"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Data seluler dinonaktifkan"</string>
@@ -202,15 +205,12 @@
     <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Layar Transmisi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
-    <!-- no translation found for quick_settings_inversion_label (8790919884718619648) -->
-    <skip />
+    <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inversi warna"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode koreksi warna"</string>
-    <!-- no translation found for quick_settings_more_settings (326112621462813682) -->
-    <skip />
-    <!-- no translation found for quick_settings_tethering_label (7153452060448575549) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_label (6046917934974004879) -->
-    <skip />
+    <string name="quick_settings_more_settings" msgid="326112621462813682">"Setelan lainnya"</string>
+    <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Menambatkan"</string>
+    <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Pemberitahuan"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"TERBARU"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
@@ -227,8 +227,16 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d lainnya"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Pemberitahuan kurang darurat di bawah"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Ketuk lagi untuk membuka"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hingga Anda menonaktifkan ini"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item>
+    <item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
+    <item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 412d001..6cf13be 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Posizione: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Allarme impostato per: <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Chiudi riquadro"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Più tempo"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Meno tempo"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Dati 2G-3G disattivati"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dati 4G disattivati"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dati mobili disattivati"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Altre impostazioni"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifiche"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"MESSAGGI RECENTI"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notifiche meno urgenti in basso"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tocca ancora per aprire"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Scorri verso l\'alto per sbloccare"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Per un minuto"</item>
+    <item quantity="other" msgid="6924190729213550991">"Per %d minuti"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Per un\'ora"</item>
+    <item quantity="other" msgid="5408537517529822157">"Per %d ore"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 33a6701..4f07006 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"‏Bluetooth ‏<xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"המיקום <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"ההתראה נקבעה ל-<xliff:g id="TIME">%s</xliff:g>."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"‏נתוני 2G-3G מושבתים"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"‏נתוני 4G מושבתים"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"נתונים לנייד מושבתים"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"הגדרות נוספות"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"שיתוף אינטרנט בין ניידים"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"נקודה לשיתוף אינטרנט"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"הודעות"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"אחרונים"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"הודעות בדחיפות נמוכה יותר בהמשך"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"הקש שוב כדי לפתוח"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"החלק מעלה כדי לבטל את הנעילה"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"עד שתכבה"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"למשך דקה אחת"</item>
+    <item quantity="other" msgid="6924190729213550991">"‏למשך %d דקות"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"למשך שעה אחת"</item>
+    <item quantity="other" msgid="5408537517529822157">"‏למשך %d שעות"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 3ed729b..84bbf8b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -158,6 +158,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"現在地: <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"アラームは<xliff:g id="TIME">%s</xliff:g>に設定されています。"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G~3Gデータが無効になりました"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4Gデータが無効になりました"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"モバイルデータが無効になりました"</string>
@@ -209,6 +215,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"詳細設定"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"テザリング"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"アクセスポイント"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"最近"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
@@ -228,4 +236,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"緊急度の低い通知を下に表示"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"開くにはもう一度タップしてください"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ロック解除するには上にスワイプしてください"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 506ec3d..c31ea24 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"მდებარეობა <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"მაღვიძარა დაყენებულია: <xliff:g id="TIME">%s</xliff:g>"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G ინტერნეტი გაითიშა."</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G მონაცემები გათიშულია"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"მობილური ინტერნეტი გაითიშა."</string>
@@ -202,11 +208,13 @@
     <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string>
-    <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ინვერტირება"</string>
+    <string name="quick_settings_inversion_label" msgid="8790919884718619648">"ფერების შებრუნება"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"ფერთა კორექციის რეჟიმი"</string>
     <string name="quick_settings_more_settings" msgid="326112621462813682">"დამატებითი პარამეტრები"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"მოდემის რეჟიმი"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"წვდომის წერტილი"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"ბოლო დროის"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
@@ -223,8 +231,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d სხვა"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"ქვემოთ მითითებულია ნაკლებად სასწრაფო შეტყობინებები"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"შეეხეთ ისევ გასახსნელად"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"გაასრიალეთ ზევით განსაბლოკად"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index f3b4e9e..a9cf7d6 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -64,7 +64,7 @@
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់…"</string>
     <string name="screenshot_saving_title" msgid="8242282144535555697">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"រូបថត​អេក្រង់​កំពុង​ត្រូវ​បាន​រក្សាទុក។"</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"បាន​ចាប់​យក​រូបថត​អេក្រង់។​"</string>
+    <string name="screenshot_saved_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>
@@ -140,7 +140,7 @@
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"សម្អាត​ការ​ជូន​ដំណឹង។"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"បាន​បើក GPS ។"</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"ទទួល​​ GPS ។"</string>
-    <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បាន​បើក​ម៉ាស៊ីន​អង្គុលីលេខ​"</string>
+    <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បាន​បើក​ម៉ាស៊ីន​អង្គុលីលេខ"</string>
     <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"កម្មវិធី​រោទ៍​ញ័រ។"</string>
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"កម្មវិធី​រោទ៍​ស្ងាត់។"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"ប៊្លូធូស <xliff:g id="STATE">%s</xliff:g> ។"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"ទីតាំង <xliff:g id="STATE">%s</xliff:g> ។"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"កំណត់​សំឡេង​រោទ៍​សម្រាប់ <xliff:g id="TIME">%s</xliff:g> ។"</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"បាន​បិទ​ទិន្នន័យ 2G-3G"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"បាន​បិទ​ទិន្នន័យ 4G"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"បាន​បិទ​ទិន្នន័យ​ចល័ត"</string>
@@ -187,7 +190,7 @@
     <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"ចាក់​សោ​​បញ្ឈរ"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ចាក់​សោ​​​ផ្ដេក"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"វិធីសាស្ត្រ​បញ្ចូល"</string>
-    <string name="quick_settings_location_label" msgid="5011327048748762257">"ទី​តាំង​"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"ទី​តាំង"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"ទីតាំង​បាន​បិទ"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"ឧបករណ៍​មេឌៀ"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
@@ -207,10 +210,11 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ការ​កំណត់​ច្រើន​ទៀត"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ការ​ភ្ជាប់"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ហតស្ប៉ត"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"ការ​ជូនដំណឹង"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"ថ្មីៗ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
-    <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញ​អាច​\nត្រូវ​បាន​ត្រួតពិនិត្យ​"</string>
+    <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញ​អាច​\nត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
     <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>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ការ​ជូន​ដំណឹង​​មិន​សូវ​បន្ទាន់​ខាង​ក្រោម"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ប៉ះ​ម្ដង​ទៀត ដើម្បី​បើក"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"អូស​ឡើង​លើ ដើម្បី​ដោះ​សោ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"រហូត​ដល់ពេល​​អ្នក​បិទ​វា"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"សម្រាប់​មួយ​នាទី"</item>
+    <item quantity="other" msgid="6924190729213550991">"សម្រាប់ %d នាទី"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"សម្រាប់​មួយ​ម៉ោង"</item>
+    <item quantity="other" msgid="5408537517529822157">"សម្រាប់ %d ម៉ោង"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2b39e14..bb2e5c1 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"블루투스 <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"위치 <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"알람이 <xliff:g id="TIME">%s</xliff:g>(으)로 설정되었습니다."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G 데이터 사용중지됨"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G 데이터 사용중지됨"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"모바일 데이터 사용중지됨"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"설정 더보기"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"테더링"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"핫스팟"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"알림"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"최근"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"아래에 덜 급한 알림 표시"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"다시 탭하여 열기"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"위로 스와이프하여 잠금 해제"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"이 기능을 사용 중지할 때까지"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"1분 동안"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d분 동안"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"1시간 동안"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d시간 동안"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 5d2ccbc..7220777 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"ສະ​ຖານ​ທີ່ <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"ຕັ້ງໂມງປຸກ <xliff:g id="TIME">%s</xliff:g> ແລ້ວ."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"ອິນເຕີເນັດ 2G​, 3G ຖືກປິດແລ້ວ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"ການນຳໃຊ້ຂໍ້ມູນ 4G ຖືກປິດແລ້ວ"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"ອິນເຕີເນັດໃນມືຖືຖືກປິດການນຳໃຊ້ແລ້ວ"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"​ການ​ປ່ອນ​ສັນ​ຍານ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"​ຮັອດ​ສະ​ປອດ"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"ການແຈ້ງເຕືອນ"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"ບໍ່​ດົນ​ມາ​ນີ້"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"ການ​ແຈ້ງເຕືອນ​ທີ່​ສຳຄັນ​ໜ້ອຍ​ກວ່າ​ຢູ່​ດ້ານ​ລຸ່ມ"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"ແຕະ​ອີກ​ຄັ້ງ​ເພື່ອ​ເປີດ"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນ​ຂຶ້ນ​ເພື່ອ​ປົດ​ລັອກ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"ຈົນກວ່າ​ທ່ານ​ຈະ​ປິດ"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"​ສຳ​ລັບ​ນຶ່ງ​ນາ​ທີ"</item>
+    <item quantity="other" msgid="6924190729213550991">"ສຳ​ລັບ %d ນາ​ທີ"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"​ສຳ​ລັບນຶ່ງ​ຊົ່ວ​ໂມງ"</item>
+    <item quantity="other" msgid="5408537517529822157">"ສຳ​ລັບ %d ຊົ່ວ​ໂມງ"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index cede14c..d0ebd54 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"„Bluetooth“ <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Vietovė – <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Signalas nustatytas <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Uždaryti skydelį"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Daugiau laiko"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Mažiau laiko"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G–3G duomenys neleidžiami"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G duomenys neleidžiami"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilieji duomenys neleidžiami"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Daugiau nustatymų"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Susiejimas"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Viešosios interneto prieigos taškas"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Pranešimai"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"PASTARIEJI"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mažiau skubūs pranešimai toliau"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Palieskite dar kartą, kad atidarytumėte"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Perbraukite aukštyn, kad atrakintumėte"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kol išjungsite"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"1 min."</item>
+    <item quantity="other" msgid="6924190729213550991">"%d min."</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"1 val."</item>
+    <item quantity="other" msgid="5408537517529822157">"%d val."</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 280ce40..23ce4a9 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth statuss: <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Atrašanās vieta: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Signāls ir iestatīts uz: <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Aizvērt paneli"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Ilgāk"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Mazāks laiks"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G–3G dati atspējoti"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G dati atspējoti"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilie dati atspējoti"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Vairāk iestatījumu"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Piesaiste"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tīklājs"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Paziņojumi"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"JAUNĀKIE"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mazāk steidzami paziņojumi tiek rādīti tālāk"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Pieskarieties vēlreiz, lai atvērtu"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Velciet uz augšu, lai atbloķētu"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Līdz brīdim, kad izslēgsiet"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Vienu minūti"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d min"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Vienu stundu"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d h"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 773a6fb..c00b7ed 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Блютүүт <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Байршил <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Сэрүүлгийг <xliff:g id="TIME">%s</xliff:g>-д тохируулсан."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G дата идэвхгүй болов"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G дата идэвхгүй байна"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобайл дата идэвхгүй болов"</string>
@@ -207,6 +213,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Өөр тохиргоо"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Модем болгох"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Сүлжээний цэг"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"СҮҮЛИЙН"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
@@ -226,4 +234,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Яаралтай биш мэдэгдлүүдийг доор"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Нээхийн тулд дахин товшино уу"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Түгжээг тайлах бол шудрана уу"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 09e52cc..263fc46 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Lokasi <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Penggera ditetapkan pada <xliff:g id="TIME">%s</xliff:g>."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Data 2G-3G dilumpuhkan"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data 4G dilumpuhkan"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Data mudah alih dilumpuhkan"</string>
@@ -207,6 +213,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Lagi tetapan"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Penambatan"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tempat liputan"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"TERBAHARU"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
@@ -223,8 +231,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d lagi"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <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>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Leret ke atas untuk membuka kunci"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 7ffd381..75706a2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth – <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Posisjon <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarmen ble stilt for <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Lukk panelet"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Mer tid"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Mindre tid"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G-data er deaktivert"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-data er deaktivert"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobildata er deaktivert"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere innstillinger"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tilknytning"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Wi-Fi-sone"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Varsler"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"NYLIGE"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende varsler nedenfor"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Trykk på nytt for å åpne"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Sveip oppover for å låse opp"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Inntil du slår av funksjonen"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"I ett minutt"</item>
+    <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"I én time"</item>
+    <item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index e79adf9..c4bef68 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Locatie <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm is ingesteld op <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Deelvenster sluiten"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Meer tijd"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Minder tijd"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-/3G-gegevens uitgeschakeld"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-gegevens uitgeschakeld"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobiele gegevens uitgeschakeld"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellingen"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Meldingen"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Minder urgente meldingen onderaan"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tik nogmaals om te openen"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Veeg omhoog om te ontgrendelen"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat u dit uitschakelt"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Eén minuut"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d minuten"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Eén uur"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d uur"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index aec7e87..825dfec 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Lokalizacja <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm ustawiony na <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Zamknij panel"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Więcej czasu"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Mniej czasu"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Wyłączono transmisję danych 2G/3G"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Wyłączono transmisję danych 4G"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Transmisja danych została wyłączona"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Więcej ustawień"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Powiązanie"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Punkt dostępu"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Powiadomienia"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"OSTATNIE"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Poniżej widać mniej pilne powiadomienia"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Kliknij ponownie, by otworzyć"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Przesuń w górę, by odblokować"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dopóki nie wyłączysz"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Przez minutę"</item>
+    <item quantity="other" msgid="6924190729213550991">"Przez %d min"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Przez godzinę"</item>
+    <item quantity="other" msgid="5408537517529822157">"Przez %d godz."</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 93c7f60..f9ac828 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Localização <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarme definido para <xliff:g id="TIME">%s</xliff:g>."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Os dados 2G-3G estão desativados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Os dados 4G estão desativados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Os dados móveis estão desativados"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mais definições"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Associação"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificações"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
@@ -226,4 +230,13 @@
     <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>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar rapidamente com o dedo para cima para desbloquear"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Durante um minuto"</item>
+    <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Durante uma hora"</item>
+    <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 079c8f0..1c13e62 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -158,6 +158,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Localização <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarme definido para <xliff:g id="TIME">%s</xliff:g>."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Dados 2G e 3G desativados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dados 4G desativados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dados móveis desativados"</string>
@@ -204,14 +210,12 @@
     <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Transmitir tela"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
-    <!-- no translation found for quick_settings_inversion_label (8790919884718619648) -->
-    <skip />
+    <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter cores"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string>
-    <!-- no translation found for quick_settings_more_settings (326112621462813682) -->
-    <skip />
-    <!-- no translation found for quick_settings_tethering_label (7153452060448575549) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_label (6046917934974004879) -->
+    <string name="quick_settings_more_settings" msgid="326112621462813682">"Mais configurações"</string>
+    <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
+    <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
     <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do aplicativo"</string>
@@ -229,8 +233,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <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>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslize para cima para desbloquear"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index b9d121a..00bf8c0 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -282,6 +282,12 @@
     <skip />
     <!-- no translation found for accessibility_quick_settings_alarm (3959908972897295660) -->
     <skip />
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <!-- no translation found for data_usage_disabled_dialog_3g_title (5257833881698644687) -->
     <skip />
     <!-- no translation found for data_usage_disabled_dialog_4g_title (4789143363492682629) -->
@@ -384,6 +390,8 @@
     <skip />
     <!-- no translation found for quick_settings_hotspot_label (6046917934974004879) -->
     <skip />
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <!-- no translation found for recents_empty_message (2269156590813544104) -->
     <skip />
     <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
@@ -411,4 +419,10 @@
     <skip />
     <!-- no translation found for keyguard_unlock (8043466894212841998) -->
     <skip />
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 10afe88..7ffa77c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Locație: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarmă setată pentru <xliff:g id="TIME">%s</xliff:g>."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Datele 2G-3G au fost dezactivate"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datele 4G au fost dezactivate"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Datele mobile au fost dezactivate"</string>
@@ -207,6 +213,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mai multe setări"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
@@ -223,8 +231,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"Încă %d"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificările mai puțin urgente mai jos"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Atingeți din nou pentru a deschide"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Glisați în sus pentru a debloca"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c726014..d726428 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Доступ к геоданным <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Будильник установлен на <xliff:g id="TIME">%s</xliff:g>"</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Передача данных по каналам 2G и 3G отключена"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Передача данных по каналу 4G отключена"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Моб. Интернет отключен"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Дополнительные настройки"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступа"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Уведомления"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"НЕДАВНИЕ СООБЩЕНИЯ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Показать менее важные оповещения"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Нажмите ещё раз, чтобы открыть"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Для разблокировки проведите пальцем по экрану"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"1 мин."</item>
+    <item quantity="other" msgid="6924190729213550991">"%d мин."</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"1 ч."</item>
+    <item quantity="other" msgid="5408537517529822157">"%d ч."</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 45bb2ad..8debc9a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -158,6 +158,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Poloha: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Budík nastavený na <xliff:g id="TIME">%s</xliff:g>."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Dátové prenosy 2G a 3G sú zakázané"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Dátové prenosy 4G sú zakázané"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilné dátové prenosy sú zakázané"</string>
@@ -209,6 +215,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Ďalšie nastavenia"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Zdieľanie dátového pripojenia"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"NEDÁVNE"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
@@ -228,4 +236,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Menej naliehavé upozornenia sa nachádzajú nižšie"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Upozornenie otvoríte opätovným klepnutím"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zariadenie odomknete prejdením prstom nahor"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 99470d6..6171c16 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Lokacija: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm je nastavljen na <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Zapri podokno"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Daljši čas"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Krajši čas"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Podatki 2G-3G so onemogočeni"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Podatki 4G so onemogočeni"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobilni podatki so onemogočeni"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Več nastavitev"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internet prek mobilne naprave"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Dostopna točka"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obvestila"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNI"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Manj nujna obvestila spodaj"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Znova se dotaknite, da odprete"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Povlecite, da odklenete"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokler tega ne izklopite"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item>
+    <item quantity="other" msgid="6924190729213550991">"Za %d min"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Za eno uro"</item>
+    <item quantity="other" msgid="5408537517529822157">"Za %d h"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1e40ed6..14782e6 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Локација је <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Аларм је подешен за <xliff:g id="TIME">%s</xliff:g>."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G–3G подаци су онемогућени"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G подаци су онемогућени"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Подаци мобилне мреже су онемогућени"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Још подешавања"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Повезивање"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Хотспот"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Обавештења"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"НАЈНОВИЈЕ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Мање хитна обавештења су у наставку"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Додирните поново да бисте отворили"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Превуците нагоре да бисте откључали"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Док не искључите"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Један минут"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d мин"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Један сат"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d с"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e4d7471..a7fb15d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Plats <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarmet ringer <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Stäng panelen"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Längre tid"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Kortare tid"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Data via 2G-3G har inaktiverats"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data via 4G har inaktiverats"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobildata har inaktiverats"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Fler inställningar"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internetdelning"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Trådlös surfzon"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Aviseringar"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"NYA"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre brådskande aviseringar nedan"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Dra uppåt om du vill låsa upp"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Tills du inaktiverar detta"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"I en minut"</item>
+    <item quantity="other" msgid="6924190729213550991">"I %d minuter"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"I en timme"</item>
+    <item quantity="other" msgid="5408537517529822157">"I %d timmar"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1d27854..b8d8c58 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -154,6 +154,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Mahali <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Kengele imewekwa <xliff:g id="TIME">%s</xliff:g>."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Data ya 2G-3G imelemazwa"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Data ya 4G imelemazwa"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Data ya kifaa cha mkononi imelemazwa"</string>
@@ -205,6 +211,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mipangilio zaidi"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Kusambaza mtandao"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Mtandao-hewa"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"YA HIVI KARIBUNI"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
@@ -221,7 +229,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d zaidi"</item>
   </plurals>
-    <string name="speed_bump_explanation" msgid="1288875699658819755">"Arifa zisizokuwa za dharura sana hapo chini"</string>
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Arifa zisizo za dharura sana ziko hapo chini"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Gonga tena ili ufungue"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Telezesha kidole ili ufungue"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 22815f3..5750faa 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -57,6 +57,6 @@
 
     <!-- The margin between the clock and the notifications on Keyguard. See
          keyguard_clock_height_fraction_* for the difference between min and max.-->
-    <dimen name="keyguard_clock_notifications_margin_min">32dp</dimen>
-    <dimen name="keyguard_clock_notifications_margin_max">32dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 306416b..dc75e78 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"บลูทูธ <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"สถานที่ <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"ตั้งเวลาปลุกไว้ที่ <xliff:g id="TIME">%s</xliff:g>"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"ปิดใช้งานข้อมูล 2G-3G แล้ว"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"ปิดใช้งานข้อมูล 4G แล้ว"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"ปิดใช้งานข้อมูลมือถือแล้ว"</string>
@@ -207,6 +213,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"การตั้งค่าเพิ่มเติม"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"การปล่อยสัญญาณ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ฮอตสปอต"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"ล่าสุด"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
@@ -223,7 +231,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"อีก %d"</item>
   </plurals>
-    <string name="speed_bump_explanation" msgid="1288875699658819755">"การแจ้งเตือนที่เร่งด่วนน้อยทางด้านล่าง"</string>
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"การแจ้งเตือนที่เร่งด่วนน้อยด้านล่าง"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"แตะอีกครั้งเพื่อเปิด"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"กวาดขึ้นเพื่อปลดล็อก"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index debef15..0713ddd 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"<xliff:g id="STATE">%s</xliff:g> ng Bluetooth."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Lokasyon <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm set para sa <xliff:g id="TIME">%s</xliff:g>."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Di pinapagana ang 2G-3G na data"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Hindi pinapagana ang 4G na data"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Hindi pinapagana ang data ng mobile"</string>
@@ -202,14 +208,12 @@
     <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"I-cast ang Screen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
-    <!-- no translation found for quick_settings_inversion_label (8790919884718619648) -->
-    <skip />
+    <string name="quick_settings_inversion_label" msgid="8790919884718619648">"I-invert ang mga kulay"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode ng pagtatama ng kulay"</string>
-    <!-- no translation found for quick_settings_more_settings (326112621462813682) -->
-    <skip />
-    <!-- no translation found for quick_settings_tethering_label (7153452060448575549) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_label (6046917934974004879) -->
+    <string name="quick_settings_more_settings" msgid="326112621462813682">"Marami pang setting"</string>
+    <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Nagte-tether"</string>
+    <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
     <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"MGA KAMAKAILAN"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
@@ -227,8 +231,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d pa"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Nasa ibaba ang mga notification na hindi masyadong mahalaga"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"I-tap ulit upang buksan"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Mag-swipe pataas upang i-unlock"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 506d27e..c0ba250 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -156,6 +156,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Konum: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm saati: <xliff:g id="TIME">%s</xliff:g>."</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G verileri devre dışı bırakıldı"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G verileri devre dışı"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobil veriler devre dışı"</string>
@@ -207,6 +213,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Diğer ayarlar"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"SON İLETİLER"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
@@ -226,4 +234,10 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Daha az acil bildirimler aşağıdadır"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Açmak için tekrar hafifçe vurun"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Kilidi açmak için hızlıca yukarı kaydırın"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5b3c5b2..e149d7b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Місцезнаходження <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Сигнал установлено на <xliff:g id="TIME">%s</xliff:g>."</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Дані 2G–3G вимкнено"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Дані 4G вимкнено"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобільне передавання даних вимкнено"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Більше налаштувань"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступу"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Сповіщення"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"ОСТАННІ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Менше термінових сповіщень нижче"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Торкніться знову, щоб відкрити"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Проведіть пальцем угору, щоб розблокувати"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Доки ви не вимкнете"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Протягом хвилини"</item>
+    <item quantity="other" msgid="6924190729213550991">"Протягом %d хв"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Протягом години"</item>
+    <item quantity="other" msgid="5408537517529822157">"Протягом %d год"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index c6fddfe..f99c341 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Vị trí <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Báo thức được đặt cho <xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Đóng bảng điều khiển"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Nhiều thời gian hơn"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Ít thời gian hơn"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Đã tắt dữ liệu 2G-3G"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Đã tắt dữ liệu 4G"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Dữ liệu di động bị vô hiệu hóa"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Cài đặt khác"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Đang dùng làm điểm truy cập Internet"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Điểm phát sóng"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Thông báo"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"GẦN ĐÂY"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Thông báo ít khẩn cấp hơn bên dưới"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Nhấn lại để mở"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Vuốt lên để mở khóa"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Cho đến khi bạn tắt tính năng này"</string>
+  <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>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Trong một giờ"</item>
+    <item quantity="other" msgid="5408537517529822157">"Trong %d giờ"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c6da6ac..6940b2c 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -158,6 +158,12 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"蓝牙:<xliff:g id="STATE">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"位置信息服务<xliff:g id="STATE">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"闹钟已设置为:<xliff:g id="TIME">%s</xliff:g>。"</string>
+    <!-- no translation found for accessibility_quick_settings_close (2571790856136835943) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_more_time (5778794273488176726) -->
+    <skip />
+    <!-- no translation found for accessibility_quick_settings_less_time (101026945195230084) -->
+    <skip />
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G 数据网络已停用"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G 数据网络已停用"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"移动数据网络已停用"</string>
@@ -209,6 +215,8 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多设置"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"网络共享"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"热点"</string>
+    <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
+    <skip />
     <string name="recents_empty_message" msgid="2269156590813544104">"最近"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
@@ -225,8 +233,13 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"还有%d条"</item>
   </plurals>
-    <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
-    <skip />
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"不太紧急的通知会显示在下方"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次点按即可打开"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑动即可解锁"</string>
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
+    <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
+    <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
+    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index ce9e260..04c00f5 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"藍牙:<xliff:g id="STATE">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"定位服務<xliff:g id="STATE">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"鬧鐘已設定為:<xliff:g id="TIME">%s</xliff:g>。"</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"已停用 2G-3G 數據"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"已停用 4G 數據"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"已停用流動數據"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"網路共用"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"熱點"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"通知"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"不太緊急的通知會在下方顯示"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上快速滑動即可解鎖"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"1 小時"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index cafb688..4ffb01b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -158,6 +158,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"藍牙:<xliff:g id="STATE">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"定位服務<xliff:g id="STATE">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"鬧鐘已設定為:<xliff:g id="TIME">%s</xliff:g>。"</string>
+    <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>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"已停用 2G-3G 數據"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"已停用 4G 數據"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"已停用行動數據"</string>
@@ -209,6 +212,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"網路共用"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"無線基地台"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"通知"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
@@ -228,4 +232,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"較不緊急的通知會顯示在下方"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑動即可解鎖"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
+    <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"1 小時"</item>
+    <item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 4865f7b..4c44972 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -156,6 +156,9 @@
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"I-Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Indawo i-<xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"I-alamu isethiwe ngo-<xliff:g id="TIME">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_close" msgid="2571790856136835943">"Vala iphaneli"</string>
+    <string name="accessibility_quick_settings_more_time" msgid="5778794273488176726">"Isikhathi esiningi"</string>
+    <string name="accessibility_quick_settings_less_time" msgid="101026945195230084">"Isikhathi esingaphansi"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"idatha ye-2G-3G ivimbelwe"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Idatha ye-4G ivimbelwe"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Idatha yefoni ivimbelwe"</string>
@@ -207,6 +210,7 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Izilungiselelo eziningi"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ukusebenzisa njengemodemu"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"I-Hotspot"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Izaziso"</string>
     <string name="recents_empty_message" msgid="2269156590813544104">"OKWAKAMUVA"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
@@ -226,4 +230,13 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Izaziso ezingasheshi kakhulu ezingezansi"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Thepha futhi ukuze uvule"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swayiphela phezulu ukuze uvule"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Uze uvale lokhu"</string>
+  <plurals name="zen_mode_duration_minutes">
+    <item quantity="one" msgid="9040808414992812341">"Iminithi elilodwa"</item>
+    <item quantity="other" msgid="6924190729213550991">"Amaminithi angu-%d"</item>
+  </plurals>
+  <plurals name="zen_mode_duration_hours">
+    <item quantity="one" msgid="3480040795582254384">"Ihora elilodwa"</item>
+    <item quantity="other" msgid="5408537517529822157">"Amahora angu-%d"</item>
+  </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 8fd1206..c453618 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -20,8 +20,6 @@
         <attr name="keyCode" format="integer" />
         <!-- does this button generate longpress / repeat events? -->
         <attr name="keyRepeat" format="boolean" />
-        <!-- drawable to use for a swelling, glowing background on press -->
-        <attr name="glowBackground" format="reference" />
     </declare-styleable>
     <declare-styleable name="ToggleSlider">
         <attr name="text" format="string" />
@@ -45,12 +43,6 @@
     <declare-styleable name="BatteryMeterView">
         <attr name="frameColor" format="color" />
     </declare-styleable>
-    <declare-styleable name="SwipeAffordanceView">
-        <attr name="swipeDirection" format="enum">
-            <enum name="start" value="0" />
-            <enum name="end" value="1" />
-        </attr>
-    </declare-styleable>
     <declare-styleable name="Clock">
         <attr name="amPmStyle" format="enum">
             <enum name="normal" value="0" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e5ed3d6..4e37dbb 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -31,8 +31,6 @@
     <drawable name="recents_callout_line">#99ffffff</drawable>
     <drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
-    <color name="notification_panel_scrim_color">#A0000000</color>
-    <color name="notification_panel_scrim_color_keyguard">#80000000</color>
     <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
@@ -75,6 +73,8 @@
     <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
     <color name="recents_task_bar_dark_dismiss_color">#ff333333</color>
 
+    <color name="keyguard_affordance">#ffffffff</color>
+
     <!-- Our quantum color palette (deep teal) -->
     <color name="primary_color">#ff7fcac3</color>
     <color name="background_color_1">#ff384248</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0bd4f18..6405ae6 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -135,5 +135,8 @@
     <!-- Defines the implementation of the velocity tracker to be used for the panel expansion. Can
          be 'platform' or 'noisy' (i.e. for noisy touch screens). -->
     <string name="velocity_tracker_impl" translatable="false">platform</string>
+
+    <!-- Wait on the touch feedback this long before performing an action. -->
+    <integer name="feedback_start_delay">300</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c209434..610b376 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -196,6 +196,12 @@
     <dimen name="qs_dual_tile_height">109dp</dimen>
     <dimen name="qs_dual_tile_padding">12dp</dimen>
 
+    <!-- How far the expanded QS panel peeks from the header in collapsed state. -->
+    <dimen name="qs_peek_height">8dp</dimen>
+
+    <dimen name="zen_mode_condition_detail_button_padding">8dp</dimen>
+    <dimen name="zen_mode_condition_height">48dp</dimen>
+
     <!-- used by DessertCase -->
     <dimen name="dessert_case_cell_size">192dp</dimen>
 
@@ -246,7 +252,7 @@
     <dimen name="notification_side_padding">8dp</dimen>
 
     <!-- Z distance between notifications if they are in the stack -->
-    <dimen name="z_distance_between_notifications">2dp</dimen>
+    <dimen name="z_distance_between_notifications">1dp</dimen>
 
     <!-- The padding between the individual notification cards when dimmed. -->
     <dimen name="notification_padding_dimmed">0dp</dimen>
@@ -288,4 +294,12 @@
     <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
     <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
 
+    <!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
+    <dimen name="keyguard_min_swipe_amount">75dp</dimen>
+
+    <!-- Volume panel dialog y offset -->
+    <dimen name="volume_panel_top">16dp</dimen>
+
+    <!-- Volume panel dialog width -->
+    <dimen name="volume_panel_width">300dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f5bc353..ef3956e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -388,6 +388,12 @@
     <string name="accessibility_quick_settings_location">Location <xliff:g id="state" example="Off">%s</xliff:g>.</string>
     <!-- Content description of the alarm tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_alarm">Alarm set for <xliff:g id="time" example="Wed 3:30 PM">%s</xliff:g>.</string>
+    <!-- Content description of quick settings detail panel close button (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_close">Close panel</string>
+    <!-- Content description of zen mode time condition plus button (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_more_time">More time</string>
+    <!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_less_time">Less time</string>
 
     <!-- Title of dialog shown when 2G-3G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
     <string name="data_usage_disabled_dialog_3g_title">2G-3G data disabled</string>
@@ -512,6 +518,8 @@
     <string name="quick_settings_tethering_label">Tethering</string>
     <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_hotspot_label">Hotspot</string>
+    <!-- QuickSettings: Notifications [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_notifications_label">Notifications</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">RECENTS</string>
@@ -563,4 +571,19 @@
     <string name="keyguard_unlock">Swipe up to unlock</string>
 
     <string name="bugreport_tile_extended" translatable="false">%s\n%s (%s)</string>
+
+    <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
+    <string name="zen_mode_forever">Until you turn this off</string>
+
+    <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_duration_minutes">
+        <item quantity="one">For one minute</item>
+        <item quantity="other">For %d minutes</item>
+    </plurals>
+
+    <!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_duration_hours">
+        <item quantity="one">For one hour</item>
+        <item quantity="other">For %d hours</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 19888a8..6a12232 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -133,6 +133,32 @@
         <item name="android:fadingEdge">horizontal</item>
     </style>
 
+    <style name="TextAppearance.QS">
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ffffff</item>
+        <item name="android:fontFamily">sans-serif</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailHeader">
+        <item name="android:textSize">20sp</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailItemPrimary">
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailItemSecondary">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">#7fcac3</item>
+    </style>
+
+    <style name="TextAppearance.QS.DetailButton">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textAllCaps">true</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
     <style name="BaseBrightnessDialogContainer">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
@@ -192,9 +218,9 @@
         <item name="android:colorControlActivated">@color/system_accent_color</item>
     </style>
 
-    <style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
+    <style name="BorderlessButton" parent="@android:style/Widget.Quantum.Button.Borderless" />
 
-    <style name="QSBorderless.Tiny">
+    <style name="BorderlessButton.Tiny">
         <item name="android:minHeight">12dip</item>
         <item name="android:minWidth">12dip</item>
     </style>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6387a92..1b12cb0 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -56,6 +56,7 @@
     static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width
                                               // beyond which alpha->0
     private float mMinAlpha = 0f;
+    private float mMaxAlpha = 1f;
 
     private float mPagingTouchSlop;
     private Callback mCallback;
@@ -140,6 +141,10 @@
         mMinAlpha = minAlpha;
     }
 
+    public void setMaxAlpha(float maxAlpha) {
+        mMaxAlpha = maxAlpha;
+    }
+
     private float getAlphaForOffset(View view) {
         float viewSize = getSize(view);
         final float fadeSize = ALPHA_FADE_END * viewSize;
@@ -150,7 +155,7 @@
         } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
             result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
         }
-        return Math.max(mMinAlpha, result);
+        return Math.min(Math.max(mMinAlpha, result), mMaxAlpha);
     }
 
     private void updateAlphaFromOffset(View animView, boolean dismissable) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index d7ce255..630ba13 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,12 +42,12 @@
     private final Class<?>[] SERVICES = new Class[] {
             com.android.systemui.keyguard.KeyguardViewMediator.class,
             com.android.systemui.recent.Recents.class,
+            com.android.systemui.volume.VolumeUI.class,
             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.volume.VolumeUI.class,
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e73e904..b2872fa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -62,6 +62,7 @@
 import com.android.keyguard.analytics.Session;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
 
@@ -1316,9 +1317,10 @@
     }
 
     public StatusBarKeyguardViewManager registerStatusBar(PhoneStatusBar phoneStatusBar,
-            ViewGroup container, StatusBarWindowManager statusBarWindowManager) {
+            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
+            ScrimController scrimController) {
         mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
-                statusBarWindowManager);
+                statusBarWindowManager, scrimController);
         return mStatusBarKeyguardViewManager;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 835a5c4..c76ee8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -26,6 +26,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -35,6 +36,7 @@
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.TetheringController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.util.List;
 import java.util.Objects;
@@ -49,12 +51,12 @@
 public abstract class QSTile<TState extends State> implements Listenable {
     protected final String TAG = "QSTile." + getClass().getSimpleName();
     protected static final boolean DEBUG = false;
-    public static final int FEEDBACK_START_DELAY = 400;
 
     protected final Host mHost;
     protected final Context mContext;
     protected final H mHandler;
     protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
+    private final int mFeedbackStartDelay;
 
     private Callback mCallback;
     protected final TState mState = newTileState();
@@ -68,6 +70,7 @@
         mHost = host;
         mContext = host.getContext();
         mHandler = new H(host.getLooper());
+        mFeedbackStartDelay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
     }
 
     public boolean supportsDualTargets() {
@@ -116,6 +119,10 @@
         mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
     }
 
+    protected void postAfterFeedback(Runnable runnable) {
+        mHandler.postDelayed(runnable, mFeedbackStartDelay);
+    }
+
     // call only on tile worker looper
 
     private void handleSetCallback(Callback callback) {
@@ -213,6 +220,7 @@
         ZenModeController getZenModeController();
         TetheringController getTetheringController();
         CastController getCastController();
+        VolumeComponent getVolumeComponent();
     }
 
     public static class State {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 5eecc20..2edd8d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -84,7 +84,8 @@
             removeView(mLabel);
         }
         final Resources res = mContext.getResources();
-        mLabel = new TextView(mDual ? new ContextThemeWrapper(mContext, R.style.QSBorderless_Tiny)
+        mLabel = new TextView(mDual
+                ? new ContextThemeWrapper(mContext, R.style.BorderlessButton_Tiny)
                 : mContext);
         mLabel.setId(android.R.id.title);
         mLabel.setTextColor(res.getColor(R.color.qs_tile_text));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index c0f9bf2..191bac9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.ConnectivityManager;
 import android.provider.Settings.Global;
 
 import com.android.systemui.R;
@@ -52,10 +53,9 @@
     }
 
     private void setEnabled(boolean enabled) {
-        mSetting.setValue(enabled ? 1 : 0);
-        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", enabled);
-        mContext.sendBroadcast(intent);
+        final ConnectivityManager mgr =
+                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mgr.setAirplaneMode(enabled);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
index fa41837..07ea825 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -58,13 +58,13 @@
 
     @Override
     protected void handleClick() {
-        mHandler.postDelayed(new Runnable() {
+        postAfterFeedback(new Runnable() {
             @Override
             public void run() {
                 mHost.collapsePanels();
                 mUiHandler.post(mShowDialog);
             }
-        }, FEEDBACK_START_DELAY);
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 907c77e..6793051 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -65,12 +65,12 @@
 
     @Override
     protected void handleClick() {
-        mHandler.postDelayed(new Runnable() {
+        postAfterFeedback(new Runnable() {
             public void run() {
                 mHost.collapsePanels();
                 mUiHandler.post(mShowDialog);
             }
-        }, FEEDBACK_START_DELAY);
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
new file mode 100644
index 0000000..130f9ce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
@@ -0,0 +1,172 @@
+/*
+ * 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.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.volume.VolumePanel;
+import com.android.systemui.volume.ZenModePanel;
+
+/** Quick settings tile: Notifications **/
+public class NotificationsTile extends QSTile<NotificationsTile.NotificationsState> {
+    private final ZenModeController mZenController;
+    private final AudioManager mAudioManager;
+
+    public NotificationsTile(Host host) {
+        super(host);
+        mZenController = host.getZenModeController();
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+    @Override
+    public View createDetailView(Context context, ViewGroup root) {
+        final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
+        final View v = LayoutInflater.from(themedContext).inflate(R.layout.qs_detail, root, false);
+        final TextView title = (TextView) v.findViewById(android.R.id.title);
+        title.setText(R.string.quick_settings_notifications_label);
+        final View close = v.findViewById(android.R.id.button1);
+        close.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showDetail(false);
+            }
+        });
+        final ViewGroup content = (ViewGroup) v.findViewById(android.R.id.content);
+        final VolumeComponent volumeComponent = mHost.getVolumeComponent();
+        final VolumePanel vp = new VolumePanel(mContext, content, mZenController);
+        v.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+                volumeComponent.setVolumePanel(null);
+            }
+
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                volumeComponent.setVolumePanel(vp);
+            }
+        });
+        vp.setZenModePanelCallback(new ZenModePanel.Callback() {
+            @Override
+            public void onMoreSettings() {
+                mHost.startSettingsActivity(ZenModePanel.ZEN_SETTINGS);
+            }
+
+            @Override
+            public void onInteraction() {
+                // noop
+            }
+        });
+        vp.postVolumeChanged(AudioManager.STREAM_NOTIFICATION, AudioManager.FLAG_SHOW_UI);
+        return v;
+    }
+
+    @Override
+    protected NotificationsState newTileState() {
+        return new NotificationsState();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mZenController.addCallback(mCallback);
+            final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            mContext.registerReceiver(mReceiver, filter);
+        } else {
+            mZenController.removeCallback(mCallback);
+            mContext.unregisterReceiver(mReceiver);
+        }
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mState.zen) {
+            mZenController.setZen(false);
+        } else {
+            showDetail(true);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(NotificationsState state, Object arg) {
+        state.visible = true;
+        state.zen = arg instanceof Boolean ? (Boolean) arg : mZenController.isZen();
+        state.ringerMode = mAudioManager.getRingerMode();
+        if (state.zen) {
+            state.iconId = R.drawable.ic_qs_zen_on;
+        } else if (state.ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+            state.iconId = R.drawable.ic_qs_ringer_vibrate;
+        } else if (state.ringerMode == AudioManager.RINGER_MODE_SILENT) {
+            state.iconId = R.drawable.ic_qs_ringer_silent;
+        } else {
+            state.iconId = R.drawable.ic_qs_ringer_audible;
+        }
+        state.label = mContext.getString(R.string.quick_settings_notifications_label);
+    }
+
+    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+        @Override
+        public void onZenChanged(boolean zen) {
+            if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
+            refreshState(zen);
+        }
+    };
+
+    public static final class NotificationsState extends QSTile.State {
+        public boolean zen;
+        public int ringerMode;
+
+        @Override
+        public boolean copyTo(State other) {
+            final NotificationsState o = (NotificationsState) other;
+            final boolean changed = o.zen != zen || o.ringerMode != ringerMode;
+            o.zen = zen;
+            o.ringerMode = ringerMode;
+            return super.copyTo(other) || changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",zen=" + zen + ",ringerMode=" + ringerMode);
+            return rt;
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
+                refreshState();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
deleted file mode 100644
index c5e9b52..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
+++ /dev/null
@@ -1,108 +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.qs.tiles;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-
-/** Quick settings tile: Ringer mode **/
-public class RingerModeTile extends QSTile<RingerModeTile.IntState> {
-
-    private final AudioManager mAudioManager;
-
-    public RingerModeTile(Host host) {
-        super(host);
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-    }
-
-    @Override
-    protected IntState newTileState() {
-        return new IntState();
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        if (listening) {
-            final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
-            mContext.registerReceiver(mReceiver, filter);
-        } else {
-            mContext.unregisterReceiver(mReceiver);
-        }
-    }
-
-    @Override
-    protected void handleClick() {
-        final int oldValue = (Integer) mState.value;
-        final int newValue =
-                oldValue == AudioManager.RINGER_MODE_NORMAL ? AudioManager.RINGER_MODE_VIBRATE
-              : oldValue == AudioManager.RINGER_MODE_VIBRATE ? AudioManager.RINGER_MODE_SILENT
-              : AudioManager.RINGER_MODE_NORMAL;
-
-        mAudioManager.setRingerMode(newValue);
-    }
-
-    @Override
-    protected void handleUpdateState(IntState state, Object arg) {
-        final int ringerMode = mAudioManager.getRingerMode();
-        state.visible = true;
-        state.value = ringerMode;
-        if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
-            state.iconId = R.drawable.ic_qs_ringer_vibrate;
-            state.label = "Vibrate";
-        } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
-            state.iconId = R.drawable.ic_qs_ringer_silent;
-            state.label = "Silent";
-        } else {
-            state.iconId = R.drawable.ic_qs_ringer_audible;
-            state.label = "Audible";
-        }
-    }
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
-                refreshState();
-            }
-        }
-    };
-
-    public static class IntState extends QSTile.State {
-        public int value;
-
-        @Override
-        public boolean copyTo(State other) {
-            final IntState o = (IntState) other;
-            final boolean changed = o.value != value;
-            o.value = value;
-            return super.copyTo(other) || changed;
-        }
-
-        @Override
-        protected StringBuilder toStringBuilder() {
-            final StringBuilder rt = super.toStringBuilder();
-            rt.insert(rt.length() - 1, ",value=" + value);
-            return rt;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
deleted file mode 100644
index f30f791..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
+++ /dev/null
@@ -1,273 +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.qs.tiles;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.service.notification.Condition;
-import android.util.AttributeSet;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.RadioButton;
-import android.widget.RelativeLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-import java.util.HashSet;
-
-/** Quick settings control panel: Zen mode **/
-public class ZenModeDetail extends RelativeLayout {
-    private static final String TAG = "ZenModeDetail";
-    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
-    private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
-
-    private final H mHandler = new H();
-
-    private int mMinutesIndex = 3;
-    private Context mContext;
-    private ZenModeTile mTile;
-    private QSTile.Host mHost;
-    private ZenModeController mController;
-
-    private Switch mSwitch;
-    private ConditionAdapter mAdapter;
-
-    public ZenModeDetail(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void init(ZenModeTile tile) {
-        mTile = tile;
-        mHost = mTile.getHost();
-        mContext = getContext();
-        mController = mHost.getZenModeController();
-
-        final ImageView close = (ImageView) findViewById(android.R.id.button1);
-        close.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mTile.showDetail(false);
-            }
-        });
-        mSwitch = (Switch) findViewById(android.R.id.checkbox);
-        mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                mController.setZen(isChecked);
-            }
-        });
-        mSwitch.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final boolean isChecked = mSwitch.isChecked();
-                mController.setZen(isChecked);
-                if (!isChecked) {
-                    mTile.showDetail(false);
-                }
-            }
-        });
-
-        final View moreSettings = findViewById(android.R.id.button2);
-        moreSettings.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mHost.startSettingsActivity(ZEN_SETTINGS);
-                mTile.showDetail(false);
-            }
-        });
-        final ListView conditions = (ListView) findViewById(android.R.id.content);
-        mAdapter = new ConditionAdapter(mContext);
-        conditions.setAdapter(mAdapter);
-        mAdapter.add(updateTimeCondition());
-
-        updateZen(mController.isZen());
-    }
-
-    private Condition updateTimeCondition() {
-        final int minutes = MINUTES[mMinutesIndex];
-        final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
-        final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
-                .appendPath("countdown").appendPath(Long.toString(millis)).build();
-        final int num = minutes < 60 ? minutes : minutes / 60;
-        final String units = minutes < 60 ? "minutes" : minutes == 60 ? "hour" : "hours";
-        return new Condition(id, "For " + num + " " + units, "", "", 0, Condition.STATE_TRUE,
-                Condition.FLAG_RELEVANT_NOW);
-    }
-
-    private void editTimeCondition(int delta) {
-        final int i = mMinutesIndex + delta;
-        if (i < 0 || i >= MINUTES.length) return;
-        mMinutesIndex = i;
-        mAdapter.remove(mAdapter.getItem(0));
-        final Condition c = updateTimeCondition();
-        mAdapter.insert(c, 0);
-        select(c);
-    }
-
-    private void select(Condition condition) {
-        mController.select(condition);
-    }
-
-    private void updateZen(boolean zen) {
-        mHandler.obtainMessage(H.UPDATE_ZEN, zen ? 1 : 0, 0).sendToTarget();
-    }
-
-    private void updateConditions(Condition[] conditions) {
-        if (conditions == null) return;
-        mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
-    }
-
-    private void handleUpdateZen(boolean zen) {
-        mSwitch.setChecked(zen);
-    }
-
-    private void handleUpdateConditions(Condition[] conditions) {
-        for (int i = mAdapter.getCount() - 1; i > 0; i--) {
-            mAdapter.remove(mAdapter.getItem(i));
-        }
-        for (Condition condition : conditions) {
-            mAdapter.add(condition);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mController.addCallback(mCallback);
-        mController.requestConditions(true);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mController.removeCallback(mCallback);
-        mController.requestConditions(false);
-    }
-
-    private final class H extends Handler {
-        private static final int UPDATE_ZEN = 1;
-        private static final int UPDATE_CONDITIONS = 2;
-
-        public H() {
-            super(Looper.getMainLooper());
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == UPDATE_ZEN) {
-                handleUpdateZen(msg.arg1 == 1);
-            } else if (msg.what == UPDATE_CONDITIONS) {
-                handleUpdateConditions((Condition[])msg.obj);
-            }
-        }
-    }
-
-    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
-        @Override
-        public void onZenChanged(boolean zen) {
-            updateZen(zen);
-        }
-        public void onConditionsChanged(Condition[] conditions) {
-            updateConditions(conditions);
-        }
-    };
-
-    private final class ConditionAdapter extends ArrayAdapter<Condition> {
-        private final LayoutInflater mInflater;
-        private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
-
-        public ConditionAdapter(Context context) {
-            super(context, 0);
-            mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            final Condition condition = getItem(position);
-            final boolean enabled = condition.state == Condition.STATE_TRUE;
-
-            final View row = convertView != null ? convertView : mInflater
-                    .inflate(R.layout.qs_zen_mode_detail_condition, parent, false);
-            final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
-            mRadioButtons.add(rb);
-            rb.setEnabled(enabled);
-            rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-                @Override
-                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                    if (isChecked) {
-                        for (RadioButton otherButton : mRadioButtons) {
-                            if (otherButton == rb) continue;
-                            otherButton.setChecked(false);
-                        }
-                        select(condition);
-                    }
-                }
-            });
-            final TextView title = (TextView) row.findViewById(android.R.id.title);
-            title.setText(condition.summary);
-            title.setEnabled(enabled);
-            title.setAlpha(enabled ? 1 : .5f);
-            final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
-            button1.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    rb.setChecked(true);
-                    editTimeCondition(-1);
-                }
-            });
-
-            final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
-            button2.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    rb.setChecked(true);
-                    editTimeCondition(1);
-                }
-            });
-            title.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    rb.setChecked(true);
-                }
-            });
-            if (position != 0) {
-                button1.setVisibility(View.GONE);
-                button2.setVisibility(View.GONE);
-            }
-            if (position == 0 && mRadioButtons.size() == 1) {
-                rb.setChecked(true);
-            }
-            return row;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
deleted file mode 100644
index bfa9c19..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
+++ /dev/null
@@ -1,87 +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.qs.tiles;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-/** Quick settings tile: Zen mode **/
-public class ZenModeTile extends QSTile<QSTile.BooleanState> {
-    private final ZenModeController mController;
-
-    public ZenModeTile(Host host) {
-        super(host);
-        mController = host.getZenModeController();
-    }
-
-    @Override
-    public View createDetailView(Context context, ViewGroup root) {
-        final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
-        final ZenModeDetail v = (ZenModeDetail) LayoutInflater.from(themedContext)
-                .inflate(R.layout.qs_zen_mode_detail, root, false);
-        v.init(this);
-        return v;
-    }
-
-    @Override
-    protected BooleanState newTileState() {
-        return new BooleanState();
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        if (listening) {
-            mController.addCallback(mCallback);
-        } else {
-            mController.removeCallback(mCallback);
-        }
-    }
-
-    @Override
-    protected void handleClick() {
-        final boolean newZen = !mState.value;
-        mController.setZen(newZen);
-        if (newZen) {
-            showDetail(true);
-        }
-    }
-
-    @Override
-    protected void handleUpdateState(BooleanState state, Object arg) {
-        final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
-        state.value = zen;
-        state.visible = true;
-        state.iconId = zen ? R.drawable.ic_qs_zen_on : R.drawable.ic_qs_zen_off;
-        state.label = mContext.getString(R.string.zen_mode_title);
-    }
-
-    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
-        @Override
-        public void onZenChanged(boolean zen) {
-            if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
-            refreshState(zen);
-        }
-    };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 27881c4..65e1cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -72,8 +72,7 @@
         window.setGravity(Gravity.TOP);
         WindowManager.LayoutParams lp = window.getAttributes();
         // Offset from the top
-        lp.y = getContext().getResources().getDimensionPixelOffset(
-                com.android.internal.R.dimen.volume_panel_top);
+        lp.y = getContext().getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
         lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
         lp.privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index e3dac4a..dcd187c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -149,6 +149,7 @@
         super.onFinishInflate();
         mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
         mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
+        updateBackground();
         updateBackgroundResources();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaImageView.java
new file mode 100644
index 0000000..06dc4e6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaImageView.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.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * An ImageView which does not have overlapping renderings commands and therefore does not need a
+ * layer when alpha is changed.
+ */
+public class AlphaImageView extends ImageView {
+    public AlphaImageView(Context context) {
+        super(context);
+    }
+
+    public AlphaImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public AlphaImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index cda84cf..bf85a07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -48,6 +48,7 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
@@ -77,11 +78,12 @@
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SearchPanelView;
 import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.Locale;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -195,7 +197,7 @@
                     mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
             if (provisioned != mDeviceProvisioned) {
                 mDeviceProvisioned = provisioned;
-                updateNotificationIcons();
+                updateNotifications();
             }
             final int mode = Settings.Global.getInt(mContext.getContentResolver(),
                     Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
@@ -213,7 +215,7 @@
             // so we just dump our cache ...
             mUsersAllowingPrivateNotifications.clear();
             // ... and refresh all the notifications
-            updateNotificationIcons();
+            updateNotifications();
         }
     };
 
@@ -284,11 +286,12 @@
         public void onListenerConnected() {
             if (DEBUG) Log.d(TAG, "onListenerConnected");
             final StatusBarNotification[] notifications = getActiveNotifications();
+            final Ranking currentRanking = getCurrentRanking();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     for (StatusBarNotification sbn : notifications) {
-                        addNotificationInternal(sbn);
+                        addNotificationInternal(sbn, currentRanking);
                     }
                 }
             });
@@ -297,13 +300,14 @@
         @Override
         public void onNotificationPosted(final StatusBarNotification sbn) {
             if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
+            final Ranking currentRanking = getCurrentRanking();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     if (mNotificationData.findByKey(sbn.getKey()) != null) {
-                        updateNotificationInternal(sbn);
+                        updateNotificationInternal(sbn, currentRanking);
                     } else {
-                        addNotificationInternal(sbn);
+                        addNotificationInternal(sbn, currentRanking);
                     }
                 }
             });
@@ -312,10 +316,24 @@
         @Override
         public void onNotificationRemoved(final StatusBarNotification sbn) {
             if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
+            final Ranking currentRanking = getCurrentRanking();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    removeNotificationInternal(sbn.getKey());
+                    removeNotificationInternal(sbn.getKey(), currentRanking);
+                }
+            });
+        }
+
+        @Override
+        public void onNotificationRankingUpdate() {
+            if (DEBUG) Log.d(TAG, "onRankingUpdate");
+            final Ranking currentRanking = getCurrentRanking();
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mNotificationData.updateRanking(currentRanking);
+                    updateNotifications();
                 }
             });
         }
@@ -1120,19 +1138,13 @@
         }
     }
 
-    protected StatusBarNotification removeNotificationViews(String key) {
-        NotificationData.Entry entry = mNotificationData.remove(key);
+    protected StatusBarNotification removeNotificationViews(String key, Ranking ranking) {
+        NotificationData.Entry entry = mNotificationData.remove(key, ranking);
         if (entry == null) {
             Log.w(TAG, "removeNotification for unknown key: " + key);
             return null;
         }
-        // Remove the expanded view.
-        ViewGroup rowParent = (ViewGroup)entry.row.getParent();
-        if (rowParent != null) rowParent.removeView(entry.row);
-        updateRowStates();
-        updateNotificationIcons();
-        updateSpeedBump();
-
+        updateNotifications();
         return entry.notification;
     }
 
@@ -1166,35 +1178,17 @@
         return entry;
     }
 
-    protected void addNotificationViews(NotificationData.Entry entry) {
+    protected void addNotificationViews(Entry entry, Ranking ranking) {
         if (entry == null) {
             return;
         }
         // Add the expanded view and icon.
-        int pos = mNotificationData.add(entry);
-        if (DEBUG) {
-            Log.d(TAG, "addNotificationViews: added at " + pos);
-        }
-        updateRowStates();
-        updateNotificationIcons();
-        updateSpeedBump();
+        mNotificationData.add(entry, ranking);
+        updateNotifications();
     }
 
-    protected void updateSpeedBump() {
-        int n = mNotificationData.size();
-        int speedBumpIndex = -1;
-        for (int i = n-1; i >= 0; i--) {
-            NotificationData.Entry entry = mNotificationData.get(i);
-            if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1
-                    && entry.row.isBelowSpeedBump() ) {
-                speedBumpIndex = n - 1 - i;
-            }
-        }
-        mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
-    }
-
-    private void addNotificationViews(StatusBarNotification notification) {
-        addNotificationViews(createNotificationViews(notification));
+    private void addNotificationViews(StatusBarNotification notification, Ranking ranking) {
+        addNotificationViews(createNotificationViews(notification), ranking);
     }
 
     /**
@@ -1208,17 +1202,17 @@
     protected void updateRowStates() {
         int maxKeyguardNotifications = getMaxKeyguardNotifications();
         mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
-        int n = mNotificationData.size();
+        final int N = mNotificationData.size();
         int visibleNotifications = 0;
         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
-        for (int i = n-1; i >= 0; i--) {
+        for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = mNotificationData.get(i);
             if (onKeyguard) {
                 entry.row.setExpansionDisabled(true);
             } else {
                 entry.row.setExpansionDisabled(false);
                 if (!entry.row.isUserLocked()) {
-                    boolean top = (i == n-1);
+                    boolean top = (i == 0);
                     entry.row.setSystemExpanded(top);
                 }
             }
@@ -1245,6 +1239,9 @@
         } else {
             mKeyguardIconOverflowContainer.setVisibility(View.GONE);
         }
+        // Move overflow container to last position.
+        mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
+                mStackScroller.getChildCount() - 1);
     }
 
     private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1254,7 +1251,7 @@
     protected void setZenMode(int mode) {
         if (!isDeviceProvisioned()) return;
         mZenMode = mode;
-        updateNotificationIcons();
+        updateNotifications();
     }
 
     protected void setShowLockscreenNotifications(boolean show) {
@@ -1263,41 +1260,37 @@
 
     protected abstract void haltTicker();
     protected abstract void setAreThereNotifications();
-    protected abstract void updateNotificationIcons();
+    protected abstract void updateNotifications();
     protected abstract void tick(StatusBarNotification n, boolean firstTime);
     protected abstract void updateExpandedViewPos(int expandedPosition);
     protected abstract boolean shouldDisableNavbarGestures();
 
-    protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
-        return parent != null && parent.indexOfChild(entry.row) == 0;
-    }
-
-
     @Override
     public void addNotification(StatusBarNotification notification) {
         if (!USE_NOTIFICATION_LISTENER) {
-            addNotificationInternal(notification);
+            addNotificationInternal(notification, null);
         }
     }
 
-    public abstract void addNotificationInternal(StatusBarNotification notification);
+    public abstract void addNotificationInternal(StatusBarNotification notification,
+            Ranking ranking);
 
     @Override
     public void removeNotification(String key) {
         if (!USE_NOTIFICATION_LISTENER) {
-            removeNotificationInternal(key);
+            removeNotificationInternal(key, null);
         }
     }
 
-    protected abstract void removeNotificationInternal(String key);
+    protected abstract void removeNotificationInternal(String key, Ranking ranking);
 
     public void updateNotification(StatusBarNotification notification) {
         if (!USE_NOTIFICATION_LISTENER) {
-            updateNotificationInternal(notification);
+            updateNotificationInternal(notification, null);
         }
     }
 
-    public void updateNotificationInternal(StatusBarNotification notification) {
+    public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
         if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
 
         final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());
@@ -1369,18 +1362,12 @@
                         && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
                         && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
 
-        ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
-        boolean orderUnchanged =
-                   notification.getNotification().when == oldNotification.getNotification().when
-                && notification.getScore() == oldNotification.getScore();
-        // score now encompasses/supersedes isOngoing()
 
         boolean updateTicker = notification.getNotification().tickerText != null
                 && !TextUtils.equals(notification.getNotification().tickerText,
                 oldEntry.notification.getNotification().tickerText);
-        boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
-        if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged && publicUnchanged
-                && (orderUnchanged || isTopAnyway)) {
+        if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
+                && publicUnchanged) {
             if (DEBUG) Log.d(TAG, "reusing notification for key: " + notification.getKey());
             oldEntry.notification = notification;
             try {
@@ -1408,22 +1395,20 @@
                     handleNotificationError(notification, "Couldn't update icon: " + ic);
                     return;
                 }
-                updateRowStates();
-                updateSpeedBump();
+                mNotificationData.updateRanking(ranking);
+                updateNotifications();
             }
             catch (RuntimeException e) {
                 // It failed to add cleanly.  Log, and remove the view from the panel.
                 Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
-                removeNotificationViews(notification.getKey());
-                addNotificationViews(notification);
+                removeNotificationViews(notification.getKey(), ranking);
+                addNotificationViews(notification, ranking);
             }
         } else {
             if (DEBUG) Log.d(TAG, "not reusing notification for key: " + notification.getKey());
             if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
-            if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
-            if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
-            removeNotificationViews(notification.getKey());
-            addNotificationViews(notification);  // will also replace the heads up
+            removeNotificationViews(notification.getKey(), ranking);
+            addNotificationViews(notification, ranking);  // will also replace the heads up
             final NotificationData.Entry newEntry = mNotificationData.findByKey(
                     notification.getKey());
             final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
@@ -1570,5 +1555,12 @@
             mWindowManager.removeViewImmediate(mSearchPanelView);
         }
         mContext.unregisterReceiver(mBroadcastReceiver);
+        if (USE_NOTIFICATION_LISTENER) {
+            try {
+                mNotificationListener.unregisterAsSystemService();
+            } catch (RemoteException e) {
+                // Ignore.
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index 7d576cb..5f1325b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -18,6 +18,7 @@
 
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.view.ViewPropertyAnimator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
@@ -46,6 +47,8 @@
     private float mMaxLengthSeconds;
     private float mHighVelocityPxPerSecond;
 
+    private AnimatorProperties mAnimatorProperties = new AnimatorProperties();
+
     public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
         mMaxLengthSeconds = maxLengthSeconds;
         mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1);
@@ -80,18 +83,59 @@
      * @param currValue the current value
      * @param endValue the end value of the animator
      * @param velocity the current velocity of the motion
+     */
+    public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
+            float velocity) {
+        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
+    }
+
+    /**
+     * Applies the interpolator and length to the animator, such that the fling animation is
+     * consistent with the finger motion.
+     *
+     * @param animator the animator to apply
+     * @param currValue the current value
+     * @param endValue the end value of the animator
+     * @param velocity the current velocity of the motion
      * @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,
             float maxDistance) {
+        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
+                maxDistance);
+        animator.setDuration(properties.duration);
+        animator.setInterpolator(properties.interpolator);
+    }
+
+    /**
+     * Applies the interpolator and length to the animator, such that the fling animation is
+     * consistent with the finger motion.
+     *
+     * @param animator the animator to apply
+     * @param currValue the current value
+     * @param endValue the end value of the animator
+     * @param velocity the current velocity of the motion
+     * @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(ViewPropertyAnimator animator, float currValue, float endValue,
+            float velocity, float maxDistance) {
+        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
+                maxDistance);
+        animator.setDuration(properties.duration);
+        animator.setInterpolator(properties.interpolator);
+    }
+
+    private AnimatorProperties getProperties(float currValue,
+            float endValue, float velocity, float maxDistance) {
         float maxLengthSeconds = (float) (mMaxLengthSeconds
                 * Math.sqrt(Math.abs(endValue - currValue) / maxDistance));
         float diff = Math.abs(endValue - currValue);
         float velAbs = Math.abs(velocity);
         float durationSeconds = LINEAR_OUT_SLOW_IN_START_GRADIENT * diff / velAbs;
         if (durationSeconds <= maxLengthSeconds) {
-            animator.setInterpolator(mLinearOutSlowIn);
+            mAnimatorProperties.interpolator = mLinearOutSlowIn;
         } else if (velAbs >= mMinVelocityPxPerSecond) {
 
             // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
@@ -100,14 +144,15 @@
                     = new VelocityInterpolator(durationSeconds, velAbs, diff);
             InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
                     velocityInterpolator, mLinearOutSlowIn, mLinearOutSlowIn);
-            animator.setInterpolator(superInterpolator);
+            mAnimatorProperties.interpolator = superInterpolator;
         } else {
 
             // Just use a normal interpolator which doesn't take the velocity into account.
             durationSeconds = maxLengthSeconds;
-            animator.setInterpolator(mFastOutSlowIn);
+            mAnimatorProperties.interpolator = mFastOutSlowIn;
         }
-        animator.setDuration((long) (durationSeconds * 1000));
+        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
+        return mAnimatorProperties;
     }
 
     /**
@@ -124,6 +169,34 @@
      */
     public void applyDismissing(ValueAnimator animator, float currValue, float endValue,
             float velocity, float maxDistance) {
+        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
+                maxDistance);
+        animator.setDuration(properties.duration);
+        animator.setInterpolator(properties.interpolator);
+    }
+
+    /**
+     * Applies the interpolator and length to the animator, such that the fling animation is
+     * consistent with the finger motion for the case when the animation is making something
+     * disappear.
+     *
+     * @param animator the animator to apply
+     * @param currValue the current value
+     * @param endValue the end value of the animator
+     * @param velocity the current velocity of the motion
+     * @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(ViewPropertyAnimator animator, float currValue, float endValue,
+            float velocity, float maxDistance) {
+        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
+                maxDistance);
+        animator.setDuration(properties.duration);
+        animator.setInterpolator(properties.interpolator);
+    }
+
+    private AnimatorProperties getDismissingProperties(float currValue, float endValue,
+            float velocity, float maxDistance) {
         float maxLengthSeconds = (float) (mMaxLengthSeconds
                 * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f));
         float diff = Math.abs(endValue - currValue);
@@ -135,7 +208,7 @@
         Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, 1, y2);
         float durationSeconds = startGradient * diff / velAbs;
         if (durationSeconds <= maxLengthSeconds) {
-            animator.setInterpolator(mLinearOutFasterIn);
+            mAnimatorProperties.interpolator = mLinearOutFasterIn;
         } else if (velAbs >= mMinVelocityPxPerSecond) {
 
             // Cross fade between linear-out-faster-in and linear interpolator with current
@@ -145,14 +218,15 @@
                     = new VelocityInterpolator(durationSeconds, velAbs, diff);
             InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
                     velocityInterpolator, mLinearOutFasterIn, mLinearOutSlowIn);
-            animator.setInterpolator(superInterpolator);
+            mAnimatorProperties.interpolator = superInterpolator;
         } else {
 
             // Just use a normal interpolator which doesn't take the velocity into account.
             durationSeconds = maxLengthSeconds;
-            animator.setInterpolator(mFastOutLinearIn);
+            mAnimatorProperties.interpolator = mFastOutLinearIn;
         }
-        animator.setDuration((long) (durationSeconds * 1000));
+        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
+        return mAnimatorProperties;
     }
 
     /**
@@ -221,4 +295,10 @@
             return time * mVelocity / mDiff;
         }
     }
+
+    private static class AnimatorProperties {
+        Interpolator interpolator;
+        long duration;
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 0555879..993bb92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -50,7 +50,7 @@
         for (int i = 0; i < n; i++) {
             final StatusBarNotification sbn = mIntercepted.valueAt(i);
             sbn.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false);
-            mBar.addNotificationInternal(sbn);
+            mBar.addNotificationInternal(sbn, null);
         }
         mIntercepted.clear();
         updateSyntheticNotification();
@@ -88,7 +88,7 @@
     private void updateSyntheticNotification() {
         if (mIntercepted.isEmpty()) {
             if (mSynKey != null) {
-                mBar.removeNotificationInternal(mSynKey);
+                mBar.removeNotificationInternal(mSynKey, null);
                 mSynKey = null;
             }
             return;
@@ -107,9 +107,9 @@
                 mBar.getCurrentUserHandle());
         if (mSynKey == null) {
             mSynKey = sbn.getKey();
-            mBar.addNotificationInternal(sbn);
+            mBar.addNotificationInternal(sbn, null);
         } else {
-           mBar.updateNotificationInternal(sbn);
+           mBar.updateNotificationInternal(sbn, null);
         }
         final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey);
         entry.row.setOnClickListener(mSynClickListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 5696246..d829ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -16,15 +16,19 @@
 
 package com.android.systemui.statusbar;
 
+import android.app.Notification;
+import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.StatusBarNotification;
 import android.view.View;
-import android.widget.ImageView;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 
 /**
  * The list of currently displaying notifications.
+ *
+ * TODO: Rename to NotificationList.
  */
 public class NotificationData {
     public static final class Entry {
@@ -34,7 +38,6 @@
         public ExpandableNotificationRow row; // the outer expanded view
         public View expanded; // the inflated RemoteViews
         public View expandedPublic; // for insecure lockscreens
-        public ImageView largeIcon;
         public View expandedBig;
         private boolean interruption;
         public Entry() {}
@@ -64,18 +67,23 @@
     }
 
     private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
-    private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
-        // sort first by score, then by when
+    private Ranking mRanking;
+    private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
+        @Override
         public int compare(Entry a, Entry b) {
+            if (mRanking != null) {
+                return mRanking.getRank(a.key) - mRanking.getRank(b.key);
+            }
+
             final StatusBarNotification na = a.notification;
             final StatusBarNotification nb = b.notification;
-            int d = na.getScore() - nb.getScore();
+            int d = nb.getScore() - na.getScore();
             if (a.interruption != b.interruption) {
-                return a.interruption ? 1 : -1;
+                return a.interruption ? -1 : 1;
             } else if (d != 0) {
                 return d;
             } else {
-                return (int) (na.getNotification().when - nb.getNotification().when);
+                return (int) (nb.getNotification().when - na.getNotification().when);
             }
         }
     };
@@ -97,26 +105,47 @@
         return null;
     }
 
-    public int add(Entry entry) {
-        int i;
-        int N = mEntries.size();
-        for (i = 0; i < N; i++) {
-            if (mEntryCmp.compare(mEntries.get(i), entry) > 0) {
-                break;
-            }
-        }
-        mEntries.add(i, entry);
-        return i;
+    public void add(Entry entry, Ranking ranking) {
+        mEntries.add(entry);
+        updateRankingAndSort(ranking);
     }
 
-    public Entry remove(String key) {
+    public Entry remove(String key, Ranking ranking) {
         Entry e = findByKey(key);
-        if (e != null) {
-            mEntries.remove(e);
+        if (e == null) {
+            return null;
         }
+        mEntries.remove(e);
+        updateRankingAndSort(ranking);
         return e;
     }
 
+    public void updateRanking(Ranking ranking) {
+        updateRankingAndSort(ranking);
+    }
+
+    public boolean isAmbient(String key) {
+        // TODO: Remove when switching to NotificationListener.
+        if (mRanking == null) {
+            for (Entry entry : mEntries) {
+                if (key.equals(entry.key)) {
+                    return entry.notification.getNotification().priority ==
+                            Notification.PRIORITY_MIN;
+                }
+            }
+        } else {
+            return mRanking.isAmbient(key);
+        }
+        return false;
+    }
+
+    private void updateRankingAndSort(Ranking ranking) {
+        if (ranking != null) {
+            mRanking = ranking;
+        }
+        Collections.sort(mEntries, mRankingComparator);
+    }
+
     /**
      * Return whether there are any visible items (i.e. items without an error).
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index a2f8991..a84daef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -103,7 +103,11 @@
 
     @Override
     public int getIntrinsicHeight() {
-        return getActualHeight();
+        if (mCurrentAnimator != null) {
+            // expand animation is running
+            return getActualHeight();
+        }
+        return mIsExpanded ? getHeight() : mCollapsedHeight;
     }
 
     @Override
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 5e9ce21..994b329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -23,46 +23,34 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.MediaStore;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
 
 /**
  * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
  * text.
  */
-public class KeyguardBottomAreaView extends FrameLayout
-        implements SwipeAffordanceView.AffordanceListener {
+public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
+        UnlockMethodCache.OnUnlockMethodChangedListener {
 
     final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
 
     private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
 
-    private SwipeAffordanceView mCameraButton;
-    private SwipeAffordanceView mPhoneButton;
+    private ImageView mCameraImageView;
+    private ImageView mPhoneImageView;
     private ImageView mLockIcon;
 
-    private PowerManager mPowerManager;
     private ActivityStarter mActivityStarter;
-
-    private LockPatternUtils mLockPatternUtils;
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private UnlockMethodCache mUnlockMethodCache;
 
     public KeyguardBottomAreaView(Context context) {
         super(context);
@@ -84,20 +72,16 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mCameraButton = (SwipeAffordanceView) findViewById(R.id.camera_button);
-        mPhoneButton = (SwipeAffordanceView) findViewById(R.id.phone_button);
+        mCameraImageView = (ImageView) findViewById(R.id.camera_button);
+        mPhoneImageView = (ImageView) findViewById(R.id.phone_button);
         mLockIcon = (ImageView) findViewById(R.id.lock_icon);
-        mCameraButton.setAffordanceListener(this);
-        mPhoneButton.setAffordanceListener(this);
-        mLockPatternUtils = new LockPatternUtils(getContext());
-        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(getContext());
-        KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mCallback);
         watchForDevicePolicyChanges();
         watchForAccessibilityChanges();
         updateCameraVisibility();
         updatePhoneVisibility();
+        mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
+        mUnlockMethodCache.addListener(this);
         updateTrust();
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
     }
 
     public void setActivityStarter(ActivityStarter activityStarter) {
@@ -106,12 +90,12 @@
 
     private void updateCameraVisibility() {
         boolean visible = !isCameraDisabledByDpm();
-        mCameraButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 
     private void updatePhoneVisibility() {
         boolean visible = isPhoneVisible();
-        mPhoneButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mPhoneImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 
     private boolean isPhoneVisible() {
@@ -171,33 +155,31 @@
     }
 
     private void enableAccessibility(boolean touchExplorationEnabled) {
-        mCameraButton.enableAccessibility(touchExplorationEnabled);
-        mPhoneButton.enableAccessibility(touchExplorationEnabled);
+        mCameraImageView.setOnClickListener(touchExplorationEnabled ? this : null);
+        mCameraImageView.setClickable(touchExplorationEnabled);
+        mPhoneImageView.setOnClickListener(touchExplorationEnabled ? this : null);
+        mPhoneImageView.setClickable(touchExplorationEnabled);
     }
 
-    private void launchCamera() {
+    @Override
+    public void onClick(View v) {
+        if (v == mCameraImageView) {
+            launchCamera();
+        } else if (v == mPhoneImageView) {
+            launchPhone();
+        }
+    }
+
+    public void launchCamera() {
         mContext.startActivityAsUser(
                 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
                 UserHandle.CURRENT);
     }
 
-    private void launchPhone() {
+    public void launchPhone() {
         mActivityStarter.startActivity(PHONE_INTENT);
     }
 
-    @Override
-    public void onUserActivity(long when) {
-        mPowerManager.userActivity(when, false);
-    }
-
-    @Override
-    public void onActionPerformed(SwipeAffordanceView view) {
-        if (view == mCameraButton) {
-            launchCamera();
-        } else if (view == mPhoneButton) {
-            launchPhone();
-        }
-    }
 
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
@@ -211,28 +193,26 @@
         if (getVisibility() != VISIBLE) {
             return;
         }
-        int user = mLockPatternUtils.getCurrentUser();
-        boolean trust = !mLockPatternUtils.isSecure() ||
-                mKeyguardUpdateMonitor.getUserHasTrust(user);
-
-        int iconRes = trust ? R.drawable.ic_lock_open_24dp : R.drawable.ic_lock_24dp;
+        int iconRes = mUnlockMethodCache.isMethodInsecure()
+                ? R.drawable.ic_lock_open_24dp
+                : R.drawable.ic_lock_24dp;
         mLockIcon.setImageResource(iconRes);
     }
 
-    final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onScreenTurnedOn() {
-            updateTrust();
-        }
+    public ImageView getPhoneImageView() {
+        return mPhoneImageView;
+    }
 
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            updateTrust();
-        }
+    public ImageView getCameraImageView() {
+        return mCameraImageView;
+    }
 
-        @Override
-        public void onTrustChanged(int userId) {
-            updateTrust();
-        }
-    };
+    public ImageView getLockIcon() {
+        return mLockIcon;
+    }
+
+    @Override
+    public void onMethodSecureChanged(boolean methodSecure) {
+        updateTrust();
+    }
 }
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 9138867..b7a7b0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -54,19 +54,18 @@
         mWindowManager = windowManager;
     }
 
-    public void prepare() {
-        ensureView();
-    }
-
     public void show() {
         ensureView();
+        if (mRoot.getVisibility() == View.VISIBLE) {
+            return;
+        }
 
         // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
         // Keyguard. If we need to authenticate, show the bouncer.
         if (!mKeyguardView.dismiss()) {
             mRoot.setVisibility(View.VISIBLE);
-            mKeyguardView.requestFocus();
             mKeyguardView.onResume();
+            mKeyguardView.startAppearAnimation();
         }
     }
 
@@ -76,11 +75,15 @@
         show();
     }
 
-    public void hide() {
+    public void hide(boolean destroyView) {
         if (mKeyguardView != null) {
             mKeyguardView.cleanUp();
         }
-        removeView();
+        if (destroyView) {
+            removeView();
+        } else if (mRoot != null) {
+            mRoot.setVisibility(View.INVISIBLE);
+        }
     }
 
     /**
@@ -110,6 +113,10 @@
         return mRoot != null && mRoot.getVisibility() == View.VISIBLE;
     }
 
+    public void prepare() {
+        ensureView();
+    }
+
     private void ensureView() {
         if (mRoot == null) {
             inflateView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 769b1b1..c5c3fff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -17,7 +17,9 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
+import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.TextView;
 
 /**
@@ -50,7 +52,12 @@
     public void switchIndication(CharSequence text) {
 
         // TODO: Animation, make sure that we will show one indication long enough.
-        setText(text);
+        if (TextUtils.isEmpty(text)) {
+            setVisibility(View.INVISIBLE);
+        } else {
+            setVisibility(View.VISIBLE);
+            setText(text);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
new file mode 100644
index 0000000..b4f4865
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
@@ -0,0 +1,398 @@
+/*
+ * 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;
+    private static final float SWIPE_RESTING_ALPHA_AMOUNT = 0.7f;
+    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 PowerManager mPowerManager;
+    private final View mLeftIcon;
+    private final View mCenterIcon;
+    private final View mRightIcon;
+    private Interpolator mFastOutSlowIn;
+    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);
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        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);
+        mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
+        mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.fast_out_slow_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);
+
+        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);
+                    onUserActivity(event.getEventTime());
+                }
+                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;
+    }
+
+    private void onUserActivity(long when) {
+        mPowerManager.userActivity(when, false);
+    }
+
+    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.removeAllListeners();
+            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() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mSwipeAnimator = null;
+                mSwipingInProgress = false;
+                if (!snapBack && !mCallbackCalled) {
+
+                    // 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) {
+            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;
+        }
+    }
+
+    private 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);
+    }
+
+    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.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() {
+        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/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index c83b479..3753a72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -30,7 +30,6 @@
 
 public final class NavigationBarTransitions extends BarTransitions {
 
-    private static final float KEYGUARD_QUIESCENT_ALPHA = 0.5f;
     private static final int CONTENT_FADE_DURATION = 200;
 
     private final NavigationBarView mView;
@@ -81,8 +80,6 @@
         setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
         setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
 
-        setKeyButtonViewQuiescentAlpha(mView.getSearchLight(), KEYGUARD_QUIESCENT_ALPHA, animate);
-
         applyBackButtonQuiescentAlpha(mode, animate);
 
         // apply to lights out
@@ -96,7 +93,6 @@
 
     public void applyBackButtonQuiescentAlpha(int mode, boolean animate) {
         float backAlpha = 0;
-        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getSearchLight());
         backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getHomeButton());
         backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getRecentsButton());
         backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getMenuButton());
@@ -116,7 +112,6 @@
     public void setContentVisible(boolean visible) {
         final float alpha = visible ? 1 : 0;
         fadeContent(mView.getBackButton(), alpha);
-        fadeContent(mView.getSearchLight(), alpha);
     }
 
     private void fadeContent(View v, float alpha) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 089757a..21842bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -133,16 +133,6 @@
         }
     }
 
-    // simplified click handler to be used when device is in accessibility mode
-    private final OnClickListener mAccessibilityClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (v.getId() == R.id.search_light) {
-                KeyguardTouchDelegate.getInstance(getContext()).showAssistant();
-            }
-        }
-    };
-
     private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
         @Override
         public void onClick(View view) {
@@ -246,11 +236,6 @@
         return mCurrentView.findViewById(R.id.ime_switcher);
     }
 
-    // for when home is disabled, but search isn't
-    public View getSearchLight() {
-        return mCurrentView.findViewById(R.id.search_light);
-    }
-
     private void getIcons(Resources res) {
         mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
         mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land);
@@ -345,9 +330,6 @@
         getHomeButton()   .setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent     ? View.INVISIBLE : View.VISIBLE);
 
-        final boolean showSearch = disableHome && !disableSearch;
-        setVisibleOrGone(getSearchLight(), showSearch);
-
         mBarTransitions.applyBackButtonQuiescentAlpha(mBarTransitions.getMode(), true /*animate*/);
     }
 
@@ -402,38 +384,6 @@
         mCurrentView = mRotatedViews[Surface.ROTATION_0];
 
         getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
-
-        watchForAccessibilityChanges();
-    }
-
-    private void watchForAccessibilityChanges() {
-        final AccessibilityManager am =
-                (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-
-        // Set the initial state
-        enableAccessibility(am.isTouchExplorationEnabled());
-
-        // Watch for changes
-        am.addTouchExplorationStateChangeListener(new TouchExplorationStateChangeListener() {
-            @Override
-            public void onTouchExplorationStateChanged(boolean enabled) {
-                enableAccessibility(enabled);
-            }
-        });
-    }
-
-    private void enableAccessibility(boolean touchEnabled) {
-        Log.v(TAG, "touchEnabled:"  + touchEnabled);
-
-        // Add a touch handler or accessibility click listener for camera and search buttons
-        // for all view orientations.
-        final OnClickListener onClickListener = touchEnabled ? mAccessibilityClickListener : null;
-        for (int i = 0; i < mRotatedViews.length; i++) {
-            final View searchLight = mRotatedViews[i].findViewById(R.id.search_light);
-            if (searchLight != null) {
-                searchLight.setOnClickListener(onClickListener);
-            }
-        }
     }
 
     public boolean isVertical() {
@@ -571,7 +521,6 @@
         dumpButton(pw, "home", getHomeButton());
         dumpButton(pw, "rcnt", getRecentsButton());
         dumpButton(pw, "menu", getMenuButton());
-        dumpButton(pw, "srch", getSearchLight());
 
         pw.println("    }");
     }
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 0a44904..838e5e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,9 +21,8 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Path;
+import android.content.res.Configuration;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -32,7 +31,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
@@ -43,13 +41,17 @@
 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 {
+        View.OnClickListener, KeyguardPageSwipeHelper.Callback {
 
+    private KeyguardPageSwipeHelper mPageSwiper;
     PhoneStatusBar mStatusBar;
     private StatusBarHeaderView mHeader;
     private View mQsContainer;
+    private View mQsPanel;
     private View mKeyguardStatusView;
     private ObservableScrollView mScrollView;
     private View mStackScrollerContainer;
@@ -60,7 +62,7 @@
 
     private int mTrackingPointer;
     private VelocityTracker mVelocityTracker;
-    private boolean mTracking;
+    private boolean mQsTracking;
 
     /**
      * Whether we are currently handling a motion gesture in #onInterceptTouchEvent, but haven't
@@ -68,6 +70,7 @@
      */
     private boolean mIntercepting;
     private boolean mQsExpanded;
+    private boolean mKeyguardShowing;
     private float mInitialHeightOnTouch;
     private float mInitialTouchX;
     private float mInitialTouchY;
@@ -77,6 +80,7 @@
     private int mQsMinExpansionHeight;
     private int mQsMaxExpansionHeight;
     private int mMinStackHeight;
+    private int mQsPeekHeight;
     private float mNotificationTranslation;
     private int mStackScrollerIntrinsicPadding;
     private boolean mQsExpansionEnabled = true;
@@ -92,6 +96,11 @@
             new KeyguardClockPositionAlgorithm();
     private KeyguardClockPositionAlgorithm.Result mClockPositionResult =
             new KeyguardClockPositionAlgorithm.Result();
+    private boolean mIsSwipedHorizontally;
+    private boolean mIsExpanding;
+    private KeyguardBottomAreaView mKeyguardBottomArea;
+    private boolean mBlockTouches;
+    private ArrayList<View> mSwipeTranslationViews = new ArrayList<>();
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -121,6 +130,7 @@
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
         mStackScrollerContainer = findViewById(R.id.notification_container_parent);
         mQsContainer = findViewById(R.id.quick_settings_container);
+        mQsPanel = findViewById(R.id.quick_settings_panel);
         mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
         mScrollView.setListener(this);
         mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -128,6 +138,10 @@
         mNotificationStackScroller.setOnHeightChangedListener(this);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_slow_in);
+        mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
+        mSwipeTranslationViews.add(mNotificationStackScroller);
+        mSwipeTranslationViews.add(mKeyguardStatusView);
+        mPageSwiper = new KeyguardPageSwipeHelper(this, getContext());
     }
 
     @Override
@@ -139,22 +153,21 @@
         mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
         mStatusBarMinHeight = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
+        mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height);
         mClockPositionAlgorithm.loadDimens(getResources());
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (!mQsExpanded) {
-            positionClockAndNotifications();
-            mNotificationStackScroller.setStackHeight(getExpandedHeight());
-        }
 
         // Calculate quick setting heights.
-        mQsMinExpansionHeight = mHeader.getCollapsedHeight();
+        mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight;
         mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
-        if (mQsExpansionHeight == 0) {
-            mQsExpansionHeight = mQsMinExpansionHeight;
+        if (!mQsExpanded) {
+            setQsExpansion(mQsMinExpansionHeight);
+            positionClockAndNotifications();
+            mNotificationStackScroller.setStackHeight(getExpandedHeight());
         }
     }
 
@@ -165,7 +178,8 @@
     private void positionClockAndNotifications() {
         boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
         if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
-            mStackScrollerIntrinsicPadding = mHeader.getBottom() + mNotificationTopPadding;
+            mStackScrollerIntrinsicPadding = mHeader.getBottom() + mQsPeekHeight
+                    + mNotificationTopPadding;
             mTopPaddingAdjustment = 0;
         } else {
             mClockPositionAlgorithm.setup(
@@ -246,6 +260,12 @@
         mQsExpansionEnabled = qsExpansionEnabled;
     }
 
+    public void resetViews() {
+        mBlockTouches = false;
+        mPageSwiper.reset();
+        closeQs();
+    }
+
     public void closeQs() {
         cancelAnimation();
         setQsExpansion(mQsMinExpansionHeight);
@@ -262,9 +282,7 @@
     public void fling(float vel, boolean always) {
         GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
         if (gr != null) {
-            gr.tag(
-                "fling " + ((vel > 0) ? "open" : "closed"),
-                "notifications,v=" + vel);
+            gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
         }
         super.fling(vel, always);
     }
@@ -282,6 +300,9 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (mBlockTouches) {
+            return false;
+        }
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
         if (pointerIndex < 0) {
             pointerIndex = 0;
@@ -297,7 +318,7 @@
                 mInitialTouchX = x;
                 initVelocityTracker();
                 trackMovement(event);
-                if (shouldIntercept(mInitialTouchX, mInitialTouchY, 0)) {
+                if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
                     getParent().requestDisallowInterceptTouchEvent(true);
                 }
                 break;
@@ -315,7 +336,7 @@
             case MotionEvent.ACTION_MOVE:
                 final float h = y - mInitialTouchY;
                 trackMovement(event);
-                if (mTracking) {
+                if (mQsTracking) {
 
                     // Already tracking because onOverscrolled was called. We need to update here
                     // so we don't stop for a frame until the next touch event gets handled in
@@ -326,12 +347,12 @@
                     return true;
                 }
                 if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
-                        && shouldIntercept(mInitialTouchX, mInitialTouchY, h)) {
+                        && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
                     onQsExpansionStarted();
                     mInitialHeightOnTouch = mQsExpansionHeight;
                     mInitialTouchY = y;
                     mInitialTouchX = x;
-                    mTracking = true;
+                    mQsTracking = true;
                     mIntercepting = false;
                     return true;
                 }
@@ -340,9 +361,9 @@
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 trackMovement(event);
-                if (mTracking) {
-                    flingWithCurrentVelocity();
-                    mTracking = false;
+                if (mQsTracking) {
+                    flingQsWithCurrentVelocity();
+                    mQsTracking = false;
                 }
                 mIntercepting = false;
                 break;
@@ -353,13 +374,15 @@
     @Override
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
 
-        // Block request so we can still intercept the scrolling when QS is expanded.
-        if (!mQsExpanded) {
-            super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        // Block request when interacting with the scroll view so we can still intercept the
+        // scrolling when QS is expanded.
+        if (mScrollView.isDispatchingTouchEvent()) {
+            return;
         }
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
     }
 
-    private void flingWithCurrentVelocity() {
+    private void flingQsWithCurrentVelocity() {
         float vel = getCurrentVelocity();
 
         // TODO: Better logic whether we should expand or not.
@@ -368,65 +391,83 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
+        if (mBlockTouches) {
+            return false;
+        }
         // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
         // implementation.
-        if (mTracking) {
-            int pointerIndex = event.findPointerIndex(mTrackingPointer);
-            if (pointerIndex < 0) {
-                pointerIndex = 0;
-                mTrackingPointer = event.getPointerId(pointerIndex);
+        if (!mIsExpanding && !mQsExpanded && mStatusBar.getBarState() != StatusBarState.SHADE) {
+            mPageSwiper.onTouchEvent(event);
+            if (mPageSwiper.isSwipingInProgress()) {
+                return true;
             }
-            final float y = event.getY(pointerIndex);
-            final float x = event.getX(pointerIndex);
-
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN:
-                    mTracking = true;
-                    mInitialTouchY = y;
-                    mInitialTouchX = x;
-                    onQsExpansionStarted();
-                    mInitialHeightOnTouch = mQsExpansionHeight;
-                    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);
-                        mInitialHeightOnTouch = mQsExpansionHeight;
-                        mInitialTouchY = newY;
-                        mInitialTouchX = newX;
-                    }
-                    break;
-
-                case MotionEvent.ACTION_MOVE:
-                    final float h = y - mInitialTouchY;
-                    setQsExpansion(h + mInitialHeightOnTouch);
-                    trackMovement(event);
-                    break;
-
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    mTracking = false;
-                    mTrackingPointer = -1;
-                    trackMovement(event);
-                    flingWithCurrentVelocity();
-                    if (mVelocityTracker != null) {
-                        mVelocityTracker.recycle();
-                        mVelocityTracker = null;
-                    }
-                    break;
-            }
-            return true;
+        }
+        if (mQsTracking || mQsExpanded) {
+            return onQsTouch(event);
         }
 
-        // Consume touch events when QS are expanded.
-        return mQsExpanded || super.onTouchEvent(event);
+        super.onTouchEvent(event);
+        return true;
+    }
+
+    @Override
+    protected boolean hasConflictingGestures() {
+        return mStatusBar.getBarState() != StatusBarState.SHADE;
+    }
+
+    private boolean onQsTouch(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:
+                mQsTracking = true;
+                mInitialTouchY = y;
+                mInitialTouchX = x;
+                onQsExpansionStarted();
+                mInitialHeightOnTouch = mQsExpansionHeight;
+                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);
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    mInitialTouchY = newY;
+                    mInitialTouchX = newX;
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final float h = y - mInitialTouchY;
+                setQsExpansion(h + mInitialHeightOnTouch);
+                trackMovement(event);
+                break;
+
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mQsTracking = false;
+                mTrackingPointer = -1;
+                trackMovement(event);
+                flingQsWithCurrentVelocity();
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.recycle();
+                    mVelocityTracker = null;
+                }
+                break;
+        }
+        return true;
     }
 
     @Override
@@ -436,7 +477,7 @@
             mInitialHeightOnTouch = mQsExpansionHeight;
             mInitialTouchY = mLastTouchY;
             mInitialTouchX = mLastTouchX;
-            mTracking = true;
+            mQsTracking = true;
         }
     }
 
@@ -453,29 +494,38 @@
         setQsExpansion(height);
     }
 
-    private void expandQs() {
-        mHeader.setExpanded(true);
-        mNotificationStackScroller.setEnabled(false);
-        mScrollView.setVisibility(View.VISIBLE);
-        mQsExpanded = true;
+    private void setQsExpanded(boolean expanded) {
+        boolean changed = mQsExpanded != expanded;
+        if (changed) {
+            mQsExpanded = expanded;
+            updateQsState();
+        }
     }
 
-    private void collapseQs() {
-        mHeader.setExpanded(false);
-        mNotificationStackScroller.setEnabled(true);
-        mScrollView.setVisibility(View.INVISIBLE);
-        mQsExpanded = false;
+    public void setKeyguardShowing(boolean keyguardShowing) {
+        mKeyguardShowing = keyguardShowing;
+        updateQsState();
+    }
+
+    private void updateQsState() {
+        mHeader.setExpanded(mQsExpanded);
+        mNotificationStackScroller.setEnabled(!mQsExpanded);
+        mQsPanel.setVisibility(mQsExpanded ? View.VISIBLE : View.INVISIBLE);
+        mQsContainer.setVisibility(mKeyguardShowing && !mQsExpanded
+                ? View.INVISIBLE
+                : View.VISIBLE);
+        mScrollView.setTouchEnabled(mQsExpanded);
     }
 
     private void setQsExpansion(float height) {
         height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
         if (height > mQsMinExpansionHeight && !mQsExpanded) {
-            expandQs();
+            setQsExpanded(true);
         } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
-            collapseQs();
+            setQsExpanded(false);
         }
         mQsExpansionHeight = height;
-        mHeader.setExpansion(height);
+        mHeader.setExpansion(height - mQsPeekHeight);
         setQsTranslation(height);
         setQsStackScrollerPadding(height);
         mStatusBar.userActivity();
@@ -557,7 +607,7 @@
     /**
      * @return Whether we should intercept a gesture to open Quick Settings.
      */
-    private boolean shouldIntercept(float x, float y, float yDiff) {
+    private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
         if (!mQsExpansionEnabled) {
             return false;
         }
@@ -635,15 +685,34 @@
     protected void onExpandingStarted() {
         super.onExpandingStarted();
         mNotificationStackScroller.onExpansionStarted();
+        mIsExpanding = true;
     }
 
     @Override
     protected void onExpandingFinished() {
         super.onExpandingFinished();
         mNotificationStackScroller.onExpansionStopped();
+        mIsExpanding = false;
     }
 
     @Override
+    protected void onOverExpansionChanged(float overExpansion) {
+        float currentOverScroll = mNotificationStackScroller.getCurrentOverScrolledPixels(true);
+        mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + overExpansion
+                        - mOverExpansion, true /* onTop */, false /* animate */);
+        super.onOverExpansionChanged(overExpansion);
+    }
+
+    @Override
+    protected void onTrackingStopped(boolean expand) {
+        super.onTrackingStopped(expand);
+        mOverExpansion = 0.0f;
+        mNotificationStackScroller.setOverScrolledPixels(0.0f, true /* onTop */,
+                true /* animate */);
+    }
+
+
+    @Override
     public void onHeightChanged(ExpandableView view) {
         requestPanelHeightUpdate();
     }
@@ -657,6 +726,12 @@
     }
 
     @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        mPageSwiper.onConfigurationChanged();
+    }
+
+    @Override
     public void onClick(View v) {
         if (v == mHeader.getBackgroundView()) {
             onQsExpansionStarted();
@@ -667,4 +742,40 @@
             }
         }
     }
+
+    @Override
+    public void onAnimationToSideStarted(boolean rightPage) {
+        if (rightPage) {
+            mKeyguardBottomArea.launchCamera();
+        } else {
+            mKeyguardBottomArea.launchPhone();
+        }
+        mBlockTouches = true;
+    }
+
+
+    @Override
+    public float getPageWidth() {
+        return getWidth();
+    }
+
+    @Override
+    public ArrayList<View> getTranslationViews() {
+        return mSwipeTranslationViews;
+    }
+
+    @Override
+    public View getLeftIcon() {
+        return mKeyguardBottomArea.getPhoneImageView();
+    }
+
+    @Override
+    public View getCenterIcon() {
+        return mKeyguardBottomArea.getLockIcon();
+    }
+
+    @Override
+    public View getRightIcon() {
+        return mKeyguardBottomArea.getCameraImageView();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
index ba0b66e..ea5b309 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ScrollView;
 
@@ -28,6 +29,8 @@
 
     private Listener mListener;
     private int mLastOverscrollAmount;
+    private boolean mDispatchingTouchEvent;
+    private boolean mTouchEnabled = true;
 
     public ObservableScrollView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -37,10 +40,18 @@
         mListener = listener;
     }
 
+    public void setTouchEnabled(boolean touchEnabled) {
+        mTouchEnabled = touchEnabled;
+    }
+
     public boolean isScrolledToBottom() {
         return getScrollY() == getMaxScrollY();
     }
 
+    public boolean isDispatchingTouchEvent() {
+        return mDispatchingTouchEvent;
+    }
+
     private int getMaxScrollY() {
         int scrollRange = 0;
         if (getChildCount() > 0) {
@@ -52,6 +63,17 @@
     }
 
     @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (!mTouchEnabled) {
+            return false;
+        }
+        mDispatchingTouchEvent = true;
+        boolean result = super.dispatchTouchEvent(ev);
+        mDispatchingTouchEvent = false;
+        return result;
+    }
+
+    @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
         if (mListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 8800625..1015d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -222,7 +222,11 @@
         }
     }
 
-    public void onTrackingStopped(PanelView panel) {
+    public void onTrackingStopped(PanelView panel, boolean expand) {
         mTracking = false;
     }
+
+    public void onExpandingFinished() {
+
+    }
 }
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 8631e3a..f6db8a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -35,9 +35,10 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-public class PanelView extends FrameLayout {
+public abstract class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
     public static final String TAG = PanelView.class.getSimpleName();
+    protected float mOverExpansion;
 
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -66,6 +67,7 @@
     private float mInitialTouchX;
 
     protected void onExpandingFinished() {
+        mBar.onExpandingFinished();
     }
 
     protected void onExpandingStarted() {
@@ -128,21 +130,24 @@
         final float y = event.getY(pointerIndex);
         final float x = event.getX(pointerIndex);
 
+        boolean waitForTouchSlop = hasConflictingGestures();
+
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
-                mTracking = true;
 
                 mInitialTouchY = y;
                 mInitialTouchX = x;
+                mInitialOffsetOnTouch = mExpandedHeight;
                 if (mVelocityTracker == null) {
                     initVelocityTracker();
                 }
                 trackMovement(event);
-                if (mHeightAnimator != null) {
-                    mHeightAnimator.cancel(); // end any outstanding animations
+                if (!waitForTouchSlop || mHeightAnimator != null) {
+                    if (mHeightAnimator != null) {
+                        mHeightAnimator.cancel(); // end any outstanding animations
+                    }
+                    onTrackingStarted();
                 }
-                onTrackingStarted();
-                mInitialOffsetOnTouch = mExpandedHeight;
                 if (mExpandedHeight == 0) {
                     mJustPeeked = true;
                     runPeekAnimation();
@@ -164,15 +169,27 @@
                 break;
 
             case MotionEvent.ACTION_MOVE:
-                final float h = y - mInitialTouchY + mInitialOffsetOnTouch;
-                if (h > mPeekHeight) {
+                float h = y - mInitialTouchY;
+                if (waitForTouchSlop && !mTracking && Math.abs(h) > mTouchSlop
+                        && Math.abs(h) > Math.abs(x - mInitialTouchX)) {
+                    mInitialOffsetOnTouch = mExpandedHeight;
+                    mInitialTouchX = x;
+                    mInitialTouchY = y;
+                    if (mHeightAnimator != null) {
+                        mHeightAnimator.cancel(); // end any outstanding animations
+                    }
+                    onTrackingStarted();
+                    h = 0;
+                }
+                final float newHeight = h + mInitialOffsetOnTouch;
+                if (newHeight > mPeekHeight) {
                     if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
                         mPeekAnimator.cancel();
                     }
                     mJustPeeked = false;
                 }
-                if (!mJustPeeked) {
-                    setExpandedHeightInternal(h);
+                if (!mJustPeeked && (!waitForTouchSlop || mTracking)) {
+                    setExpandedHeightInternal(newHeight);
                     mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
                 }
 
@@ -181,25 +198,28 @@
 
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
-                mTracking = false;
                 mTrackingPointer = -1;
-                onTrackingStopped();
                 trackMovement(event);
-                flingWithCurrentVelocity();
+                boolean expand = flingWithCurrentVelocity();
+                onTrackingStopped(expand);
                 if (mVelocityTracker != null) {
                     mVelocityTracker.recycle();
                     mVelocityTracker = null;
                 }
                 break;
         }
-        return true;
+        return !waitForTouchSlop || mTracking;
     }
 
-    protected void onTrackingStopped() {
-        mBar.onTrackingStopped(PanelView.this);
+    protected abstract boolean hasConflictingGestures();
+
+    protected void onTrackingStopped(boolean expand) {
+        mTracking = false;
+        mBar.onTrackingStopped(PanelView.this, expand);
     }
 
     protected void onTrackingStarted() {
+        mTracking = true;
         mBar.onTrackingStarted(PanelView.this);
         onExpandingStarted();
     }
@@ -302,7 +322,10 @@
         mMaxPanelHeight = -1;
     }
 
-    private void flingWithCurrentVelocity() {
+    /**
+     * @return whether the panel will be expanded after the animation
+     */
+    private boolean flingWithCurrentVelocity() {
         float vel = getCurrentVelocity();
         boolean expand;
         if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -311,11 +334,16 @@
             expand = vel > 0;
         }
         fling(vel, expand);
+        return expand;
     }
 
     protected void fling(float vel, boolean expand) {
         cancelPeek();
         float target = expand ? getMaxPanelHeight() : 0.0f;
+        if (target == mExpandedHeight) {
+            onExpandingFinished();
+            return;
+        }
         ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, target);
         if (expand) {
             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
@@ -403,6 +431,11 @@
     public void setExpandedHeightInternal(float h) {
         float fh = getMaxPanelHeight();
         mExpandedHeight = Math.min(fh, h);
+        float overExpansion = h - fh;
+        overExpansion = Math.max(0, overExpansion);
+        if (overExpansion != mOverExpansion) {
+            onOverExpansionChanged(overExpansion);
+        }
 
         if (DEBUG) {
             logf("setExpansion: height=%.1f fh=%.1f tracking=%s", h, fh, mTracking ? "T" : "f");
@@ -412,6 +445,10 @@
         mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
     }
 
+    protected void onOverExpansionChanged(float overExpansion) {
+        mOverExpansion = overExpansion;
+    }
+
     protected void onHeightUpdated(float expandedHeight) {
         requestLayout();
     }
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 f8cc237..0e5b7e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -64,6 +64,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
@@ -86,7 +87,6 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -121,10 +121,12 @@
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -196,8 +198,9 @@
     NetworkControllerImpl mNetworkController;
     RotationLockControllerImpl mRotationLockController;
     UserInfoController mUserInfoController;
-    ZenModeControllerImpl mZenModeController;
+    ZenModeController mZenModeController;
     CastControllerImpl mCastController;
+    VolumeComponent mVolumeComponent;
 
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
@@ -209,6 +212,7 @@
     PhoneStatusBarView mStatusBarView;
     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
     private StatusBarWindowManager mStatusBarWindowManager;
+    private UnlockMethodCache mUnlockMethodCache;
 
     int mPixelFormat;
     Object mQueueLock = new Object();
@@ -372,6 +376,7 @@
 
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
+    private ScrimController mScrimController;
 
     private final Runnable mAutohide = new Runnable() {
         @Override
@@ -528,6 +533,7 @@
                     Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
                     mHeadsUpObserver);
         }
+        mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
         startKeyguard();
     }
 
@@ -644,9 +650,12 @@
         SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
                         R.layout.status_bar_notification_speed_bump, mStackScroller, false);
         mStackScroller.setSpeedBumpView(speedBump);
-
         mExpandedContents = mStackScroller;
 
+        mScrimController = new ScrimController(mStatusBarWindow.findViewById(R.id.scrim_behind),
+                mStatusBarWindow.findViewById(R.id.scrim_in_front));
+        mStatusBarView.setScrimController(mScrimController);
+
         mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
         mHeader.setActivityStarter(this);
         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
@@ -686,7 +695,8 @@
             mRotationLockController = new RotationLockControllerImpl(mContext);
         }
         mUserInfoController = new UserInfoController(mContext);
-        mZenModeController = new ZenModeControllerImpl(mContext, mHandler);
+        mVolumeComponent = getComponent(VolumeComponent.class);
+        mZenModeController = mVolumeComponent.getZenController();
         mCastController = new CastControllerImpl(mContext);
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
@@ -749,7 +759,7 @@
             final QSTileHost qsh = new QSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
                     mNetworkController, mZenModeController, null /*tethering*/,
-                    mCastController);
+                    mCastController, mVolumeComponent);
             for (QSTile<?> tile : qsh.getTiles()) {
                 mQSPanel.addTile(tile);
             }
@@ -781,7 +791,7 @@
     private void startKeyguard() {
         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
-                mStatusBarWindow, mStatusBarWindowManager);
+                mStatusBarWindow, mStatusBarWindowManager, mScrimController);
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
     }
 
@@ -886,7 +896,7 @@
         }
     };
 
-    View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
+    View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
         public boolean onTouch(View v, MotionEvent event) {
             switch(event.getAction()) {
             case MotionEvent.ACTION_DOWN:
@@ -921,8 +931,7 @@
 
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
-        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
-        mNavigationBarView.getSearchLight().setOnTouchListener(mHomeSearchActionListener);
+        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
         updateSearchPanel();
     }
 
@@ -972,7 +981,7 @@
 
     private void addHeadsUpView() {
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -1035,13 +1044,15 @@
     }
 
     @Override
-    public void addNotificationInternal(StatusBarNotification notification) {
+    public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
         if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore());
         Entry shadeEntry = createNotificationViews(notification);
         if (shadeEntry == null) {
             return;
         }
         if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification)) {
+            // Forward the ranking so we can sort the new notification.
+            mNotificationData.updateRanking(ranking);
             return;
         }
         if (mUseHeadsUp && shouldInterrupt(notification)) {
@@ -1081,7 +1092,7 @@
                 tick(notification, true);
             }
         }
-        addNotificationViews(shadeEntry);
+        addNotificationViews(shadeEntry, ranking);
         // Recalculate the position of the sliding windows and the titles.
         setAreThereNotifications();
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
@@ -1097,14 +1108,14 @@
     }
 
     @Override
-    public void updateNotification(StatusBarNotification notification) {
-        super.updateNotification(notification);
+    public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+        super.updateNotificationInternal(notification, ranking);
         mIntercepted.update(notification);
     }
 
     @Override
-    public void removeNotificationInternal(String key) {
-        StatusBarNotification old = removeNotificationViews(key);
+    public void removeNotificationInternal(String key, Ranking ranking) {
+        StatusBarNotification old = removeNotificationViews(key, ranking);
         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
 
         if (old != null) {
@@ -1141,7 +1152,7 @@
             R.integer.config_show_search_delay);
     }
 
-    private void loadNotificationShade() {
+    private void updateNotificationShade() {
         if (mStackScroller == null) return;
 
         int N = mNotificationData.size();
@@ -1151,7 +1162,7 @@
         final boolean provisioned = isDeviceProvisioned();
         // If the device hasn't been through Setup, we only show system notifications
         for (int i=0; i<N; i++) {
-            Entry ent = mNotificationData.get(N-i-1);
+            Entry ent = mNotificationData.get(i);
             if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
 
             // TODO How do we want to badge notifcations from profiles.
@@ -1182,26 +1193,75 @@
         for (int i=0; i<toShow.size(); i++) {
             View v = toShow.get(i);
             if (v.getParent() == null) {
-                mStackScroller.addView(v, i);
+                mStackScroller.addView(v);
             }
         }
 
+        // So after all this work notifications still aren't sorted correctly.
+        // Let's do that now by advancing through toShow and mStackScroller in
+        // lock-step, making sure mStackScroller matches what we see in toShow.
+        int j = 0;
+        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+            View child = mStackScroller.getChildAt(i);
+            if (!(child instanceof ExpandableNotificationRow)) {
+                // We don't care about non-notification views.
+                continue;
+            }
+
+            if (child == toShow.get(j)) {
+                // Everything is well, advance both lists.
+                j++;
+                continue;
+            }
+
+            // Oops, wrong notification at this position. Put the right one
+            // here and advance both lists.
+            mStackScroller.changeViewPosition(toShow.get(j), i);
+            j++;
+        }
+        updateRowStates();
+        updateSpeedbump();
         mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
     }
 
+    private void updateSpeedbump() {
+        int speedbumpIndex = -1;
+        int currentIndex = 0;
+        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 &&
+                    mNotificationData.isAmbient(entry.key)) {
+                speedbumpIndex = currentIndex;
+                break;
+            }
+            currentIndex++;
+        }
+        mStackScroller.updateSpeedBumpIndex(speedbumpIndex);
+    }
+
     @Override
-    protected void updateNotificationIcons() {
+    protected void updateNotifications() {
+        // TODO: Move this into updateNotificationIcons()?
         if (mNotificationIcons == null) return;
 
-        loadNotificationShade();
+        updateNotificationShade();
+        updateNotificationIcons();
+    }
 
+    private void updateNotificationIcons() {
         final LinearLayout.LayoutParams params
             = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
 
         int N = mNotificationData.size();
 
         if (DEBUG) {
-            Log.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons);
+            Log.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" +
+                    mNotificationIcons);
         }
 
         ArrayList<View> toShow = new ArrayList<View>();
@@ -1209,7 +1269,7 @@
         final boolean provisioned = isDeviceProvisioned();
         // If the device hasn't been through Setup, we only show system notifications
         for (int i=0; i<N; i++) {
-            Entry ent = mNotificationData.get(N-i-1);
+            Entry ent = mNotificationData.get(i);
             if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
                     || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
             if (!notificationIsForCurrentProfiles(ent.notification)) continue;
@@ -1452,6 +1512,10 @@
         startActivityDismissingKeyguard(intent, false);
     }
 
+    public ScrimController getScrimController() {
+        return mScrimController;
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -2382,7 +2446,7 @@
     public void userSwitched(int newUserId) {
         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
         animateCollapsePanels();
-        updateNotificationIcons();
+        updateNotifications();
         resetUserSetupObserver();
     }
 
@@ -2768,7 +2832,7 @@
             mKeyguardStatusView.setVisibility(View.VISIBLE);
             mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
             mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
-            mNotificationPanel.closeQs();
+            mNotificationPanel.resetViews();
         } else {
             mKeyguardStatusView.setVisibility(View.GONE);
             mKeyguardIndicationTextView.setVisibility(View.GONE);
@@ -2776,17 +2840,19 @@
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mHeader.setKeyguardShowing(true);
+            mNotificationPanel.setKeyguardShowing(true);
+            mScrimController.setKeyguardShowing(true);
         } else {
             mKeyguardBottomArea.setVisibility(View.GONE);
             mHeader.setKeyguardShowing(false);
+            mNotificationPanel.setKeyguardShowing(false);
+            mScrimController.setKeyguardShowing(false);
         }
 
         updateStackScrollerState();
         updatePublicMode();
-        updateRowStates();
-        updateSpeedBump();
+        updateNotifications();
         checkBarModes();
-        updateNotificationIcons();
         updateCarrierLabelVisibility(false);
     }
 
@@ -2879,10 +2945,15 @@
         }
     }
 
-    public void onTrackingStopped() {
+    public void onTrackingStopped(boolean expand) {
         if (mState == StatusBarState.KEYGUARD) {
             mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
         }
+        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+            if (!expand && !mUnlockMethodCache.isMethodInsecure()) {
+                showBouncer();
+            }
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 084bfcf..910d88c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -36,21 +36,16 @@
     private static final boolean DEBUG_GESTURES = true;
 
     PhoneStatusBar mBar;
-    int mScrimColor;
-    int mScrimColorKeyguard;
 
-    PanelView mFadingPanel = null;
     PanelView mLastFullyOpenedPanel = null;
     PanelView mNotificationPanel;
-    private boolean mShouldFade;
     private final PhoneStatusBarTransitions mBarTransitions;
+    private ScrimController mScrimController;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         Resources res = getContext().getResources();
-        mScrimColor = res.getColor(R.color.notification_panel_scrim_color);
-        mScrimColorKeyguard = res.getColor(R.color.notification_panel_scrim_color_keyguard);
         mBarTransitions = new PhoneStatusBarTransitions(this);
     }
 
@@ -62,6 +57,10 @@
         mBar = bar;
     }
 
+    public void setScrimController(ScrimController scrimController) {
+        mScrimController = scrimController;
+    }
+
     @Override
     public void onFinishInflate() {
         mBarTransitions.init();
@@ -110,27 +109,11 @@
     }
 
     @Override
-    public void startOpeningPanel(PanelView panel) {
-        super.startOpeningPanel(panel);
-        // we only want to start fading if this is the "first" or "last" panel,
-        // which is kind of tricky to determine
-        mShouldFade = (mFadingPanel == null || mFadingPanel.isFullyExpanded());
-        if (DEBUG) {
-            Log.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade);
-        }
-        mFadingPanel = panel;
-    }
-
-    @Override
     public void onAllPanelsCollapsed() {
         super.onAllPanelsCollapsed();
         // give animations time to settle
         mBar.makeExpandedInvisibleSoon();
-        mFadingPanel = null;
         mLastFullyOpenedPanel = null;
-        if (mScrimColor != 0 && ActivityManager.isHighEndGfx() && mBar.mStatusBarWindow != null) {
-            mBar.mStatusBarWindow.setBackgroundColor(0);
-        }
     }
 
     @Override
@@ -139,9 +122,7 @@
         if (openPanel != mLastFullyOpenedPanel) {
             openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
-        mFadingPanel = openPanel;
         mLastFullyOpenedPanel = openPanel;
-        mShouldFade = true; // now you own the fade, mister
     }
 
     @Override
@@ -163,12 +144,19 @@
     public void onTrackingStarted(PanelView panel) {
         super.onTrackingStarted(panel);
         mBar.onTrackingStarted();
+        mScrimController.onTrackingStarted();
     }
 
     @Override
-    public void onTrackingStopped(PanelView panel) {
-        super.onTrackingStopped(panel);
-        mBar.onTrackingStopped();
+    public void onTrackingStopped(PanelView panel, boolean expand) {
+        super.onTrackingStopped(panel, expand);
+        mBar.onTrackingStopped(expand);
+    }
+
+    @Override
+    public void onExpandingFinished() {
+        super.onExpandingFinished();
+        mScrimController.onExpandingFinished();
     }
 
     @Override
@@ -184,27 +172,7 @@
             Log.v(TAG, "panelExpansionChanged: f=" + frac);
         }
 
-        if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()
-                && mBar.mStatusBarWindow != null) {
-            if (mShouldFade) {
-                int scrimColor = (mBar.getBarState() == StatusBarState.KEYGUARD
-                        || mBar.getBarState() == StatusBarState.SHADE_LOCKED)
-                        ? mScrimColorKeyguard
-                        : mScrimColor;
-                frac = mPanelExpandedFractionSum; // don't judge me
-                // let's start this 20% of the way down the screen
-                frac = frac * 1.2f - 0.2f;
-                if (frac <= 0) {
-                    mBar.mStatusBarWindow.setBackgroundColor(0);
-                } else {
-                    // woo, special effects
-                    final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
-                    // attenuate background color alpha by k
-                    final int color = (int) ((scrimColor >>> 24) * k) << 24 | (scrimColor & 0xFFFFFF);
-                    mBar.mStatusBarWindow.setBackgroundColor(color);
-                }
-            }
-        }
+        mScrimController.setPanelExpansion(frac);
 
         // fade out the panel as it gets buried into the status bar to avoid overdrawing the
         // status bar on the last frame of a close animation
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 7029898..1344703 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -21,6 +21,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.tiles.AirplaneModeTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
@@ -29,11 +30,10 @@
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
 import com.android.systemui.qs.tiles.LocationTile;
-import com.android.systemui.qs.tiles.RingerModeTile;
+import com.android.systemui.qs.tiles.NotificationsTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.WifiTile;
-import com.android.systemui.qs.tiles.ZenModeTile;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.TetheringController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -60,13 +61,15 @@
     private final CastController mCast;
     private final Looper mLooper;
     private final CurrentUserTracker mUserTracker;
+    private final VolumeComponent mVolume;
     private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
+    private final int mFeedbackStartDelay;
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
             BluetoothController bluetooth, LocationController location,
             RotationLockController rotation, NetworkController network,
             ZenModeController zen, TetheringController tethering,
-            CastController cast) {
+            CastController cast, VolumeComponent volume) {
         mContext = context;
         mStatusBar = statusBar;
         mBluetooth = bluetooth;
@@ -76,6 +79,7 @@
         mZen = zen;
         mTethering = tethering;
         mCast = cast;
+        mVolume = volume;
 
         final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
         ht.start();
@@ -86,8 +90,7 @@
         mTiles.add(new ColorInversionTile(this));
         mTiles.add(new CellularTile(this));
         mTiles.add(new AirplaneModeTile(this));
-        mTiles.add(new ZenModeTile(this));
-        mTiles.add(new RingerModeTile(this));
+        mTiles.add(new NotificationsTile(this));
         mTiles.add(new RotationLockTile(this));
         mTiles.add(new LocationTile(this));
         mTiles.add(new CastTile(this));
@@ -103,6 +106,7 @@
             }
         };
         mUserTracker.startTracking();
+        mFeedbackStartDelay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
     }
 
     @Override
@@ -112,7 +116,7 @@
 
     @Override
     public void startSettingsActivity(final Intent intent) {
-        mStatusBar.postStartSettingsActivity(intent, QSTile.FEEDBACK_START_DELAY);
+        mStatusBar.postStartSettingsActivity(intent, mFeedbackStartDelay);
     }
 
     @Override
@@ -169,4 +173,9 @@
     public CastController getCastController() {
         return mCast;
     }
+
+    @Override
+    public VolumeComponent getVolumeComponent() {
+        return mVolume;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
new file mode 100644
index 0000000..6156fc3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -0,0 +1,193 @@
+/*
+ * 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.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Controls both the scrim behind the notifications and in front of the notifications (when a
+ * security method gets shown).
+ */
+public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
+
+    private static final float SCRIM_BEHIND_ALPHA = 0.62f;
+    private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.5f;
+    private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
+    private static final long ANIMATION_DURATION = 220;
+
+    private final View mScrimBehind;
+    private final View mScrimInFront;
+    private final UnlockMethodCache mUnlockMethodCache;
+
+    private boolean mKeyguardShowing;
+    private float mFraction;
+
+    private boolean mDarkenWhileDragging;
+    private boolean mBouncerShowing;
+    private boolean mAnimateChange;
+    private boolean mUpdatePending;
+    private boolean mExpanding;
+
+    private final Interpolator mInterpolator = new DecelerateInterpolator();
+
+    public ScrimController(View scrimBehind, View scrimInFront) {
+        mScrimBehind = scrimBehind;
+        mScrimInFront = scrimInFront;
+        mUnlockMethodCache = UnlockMethodCache.getInstance(scrimBehind.getContext());
+    }
+
+    public void setKeyguardShowing(boolean showing) {
+        mKeyguardShowing = showing;
+        scheduleUpdate();
+    }
+
+    public void onTrackingStarted() {
+        mExpanding = true;
+        mDarkenWhileDragging = !mUnlockMethodCache.isMethodInsecure();
+    }
+
+    public void onExpandingFinished() {
+        mExpanding = false;
+    }
+
+    public void setPanelExpansion(float fraction) {
+        mFraction = fraction;
+        scheduleUpdate();
+    }
+
+    public void setBouncerShowing(boolean showing) {
+        mBouncerShowing = showing;
+        mAnimateChange = !mExpanding;
+        scheduleUpdate();
+    }
+
+    private void scheduleUpdate() {
+        if (mUpdatePending) return;
+        mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
+        mUpdatePending = true;
+    }
+
+    private void updateScrims() {
+        if (!mKeyguardShowing) {
+            updateScrimNormal();
+            setScrimInFrontColor(0);
+        } else {
+            updateScrimKeyguard();
+        }
+        mAnimateChange = false;
+    }
+
+    private void updateScrimKeyguard() {
+        if (mExpanding && mDarkenWhileDragging) {
+            float behindFraction = Math.max(0, Math.min(mFraction, 1));
+            float fraction = 1 - behindFraction;
+            setScrimInFrontColor(fraction * SCRIM_IN_FRONT_ALPHA);
+            setScrimBehindColor(behindFraction * SCRIM_BEHIND_ALPHA_KEYGUARD);
+        } else if (mBouncerShowing) {
+            setScrimInFrontColor(SCRIM_IN_FRONT_ALPHA);
+            setScrimBehindColor(0f);
+        } else {
+            setScrimInFrontColor(0f);
+            setScrimBehindColor(SCRIM_BEHIND_ALPHA_KEYGUARD);
+        }
+    }
+
+    private void updateScrimNormal() {
+        float frac = mFraction;
+        // let's start this 20% of the way down the screen
+        frac = frac * 1.2f - 0.2f;
+        if (frac <= 0) {
+            setScrimBehindColor(0);
+        } else {
+            // woo, special effects
+            final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
+            setScrimBehindColor(k * SCRIM_BEHIND_ALPHA);
+        }
+    }
+
+    private void setScrimBehindColor(float alpha) {
+        setScrimColor(mScrimBehind, alpha);
+    }
+
+    private void setScrimInFrontColor(float alpha) {
+        setScrimColor(mScrimInFront, alpha);
+        if (alpha == 0f) {
+            mScrimInFront.setClickable(false);
+        } else {
+
+            // Eat touch events.
+            mScrimInFront.setClickable(true);
+        }
+    }
+
+    private void setScrimColor(View scrim, float alpha) {
+        int color = Color.argb((int) (alpha * 255), 0, 0, 0);
+        if (mAnimateChange) {
+            startScrimAnimation(scrim, color);
+        } else {
+            scrim.setBackgroundColor(color);
+        }
+    }
+
+    private void startScrimAnimation(final View scrim, int targetColor) {
+        int current = getBackgroundAlpha(scrim);
+        int target = Color.alpha(targetColor);
+        if (current == targetColor) {
+            return;
+        }
+        ValueAnimator anim = ValueAnimator.ofInt(current, target);
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                int value = (int) animation.getAnimatedValue();
+                scrim.setBackgroundColor(Color.argb(value, 0, 0, 0));
+            }
+        });
+        anim.setInterpolator(mInterpolator);
+        anim.setDuration(ANIMATION_DURATION);
+        anim.start();
+    }
+
+    private int getBackgroundAlpha(View scrim) {
+        if (scrim.getBackground() instanceof ColorDrawable) {
+            ColorDrawable drawable = (ColorDrawable) scrim.getBackground();
+            return Color.alpha(drawable.getColor());
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public boolean onPreDraw() {
+        mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
+        mUpdatePending = false;
+        updateScrims();
+        return true;
+    }
+}
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 389e725..3245f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -38,6 +38,11 @@
  */
 public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener {
 
+    /**
+     * How much the header expansion gets rubberbanded while expanding the panel.
+     */
+    private static final float EXPANSION_RUBBERBAND_FACTOR = 0.35f;
+
     private boolean mExpanded;
     private boolean mKeyguardShowing;
 
@@ -128,6 +133,8 @@
             updateVisibilities();
             updateSystemIconsLayoutParams();
             updateBrightnessControllerState();
+            updateZTranslation();
+            updateClickTargets();
             if (mQSPanel != null) {
                 mQSPanel.setExpanded(expanded);
             }
@@ -202,18 +209,30 @@
         }
     }
 
+    private void updateClickTargets() {
+        mDateTime.setClickable(mExpanded);
+        mMultiUserSwitch.setClickable(mExpanded);
+    }
+
+    private void updateZTranslation() {
+
+        // If we are on the Keyguard, we need to set our z position to zero, so we don't get
+        // shadows.
+        if (mKeyguardShowing && !mExpanded) {
+            setZ(0);
+        } else {
+            setTranslationZ(0);
+        }
+    }
+
     public void setExpansion(float height) {
+        height = (height - mCollapsedHeight) * EXPANSION_RUBBERBAND_FACTOR + mCollapsedHeight;
         if (height < mCollapsedHeight) {
             height = mCollapsedHeight;
         }
         if (height > mExpandedHeight) {
             height = mExpandedHeight;
         }
-        if (mExpanded) {
-            mBackground.setTranslationY(-(mExpandedHeight - height));
-        } else {
-            mBackground.setTranslationY(0);
-        }
         setClipping(height);
     }
 
@@ -247,14 +266,10 @@
 
     public void setKeyguardShowing(boolean keyguardShowing) {
         mKeyguardShowing = keyguardShowing;
-        if (keyguardShowing) {
-            setZ(0);
-        } else {
-            setTranslationZ(0);
-        }
         updateHeights();
         updateWidth();
         updateVisibilities();
+        updateZTranslation();
     }
 
     public void setUserInfoController(UserInfoController userInfoController) {
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 3849d8d..d5551b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -45,6 +45,7 @@
     private LockPatternUtils mLockPatternUtils;
     private ViewMediatorCallback mViewMediatorCallback;
     private PhoneStatusBar mPhoneStatusBar;
+    private ScrimController mScrimController;
 
     private ViewGroup mContainer;
     private StatusBarWindowManager mStatusBarWindowManager;
@@ -68,10 +69,12 @@
     }
 
     public void registerStatusBar(PhoneStatusBar phoneStatusBar,
-            ViewGroup container, StatusBarWindowManager statusBarWindowManager) {
+            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
+            ScrimController scrimController) {
         mPhoneStatusBar = phoneStatusBar;
         mContainer = container;
         mStatusBarWindowManager = statusBarWindowManager;
+        mScrimController = scrimController;
         mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
                 mStatusBarWindowManager, container);
     }
@@ -98,7 +101,7 @@
             mBouncer.show();
         } else {
             mPhoneStatusBar.showKeyguard();
-            mBouncer.hide();
+            mBouncer.hide(false /* destroyView */);
             mBouncer.prepare();
         }
     }
@@ -124,7 +127,7 @@
         if (mShowing) {
             if (mOccluded) {
                 mPhoneStatusBar.hideKeyguard();
-                mBouncer.hide();
+                mBouncer.hide(false /* destroyView */);
             } else {
                 showBouncerOrKeyguard();
             }
@@ -184,7 +187,7 @@
         mShowing = false;
         mPhoneStatusBar.hideKeyguard();
         mStatusBarWindowManager.setKeyguardShowing(false);
-        mBouncer.hide();
+        mBouncer.hide(true /* destroyView */);
         mViewMediatorCallback.keyguardGone();
         updateStates();
     }
@@ -216,7 +219,7 @@
      */
     public boolean onBackPressed() {
         if (mBouncer.isShowing()) {
-            mBouncer.hide();
+            mBouncer.hide(false /* destroyView */);
             mPhoneStatusBar.showKeyguard();
             updateStates();
             return true;
@@ -253,6 +256,7 @@
         if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
             mStatusBarWindowManager.setBouncerShowing(bouncerShowing);
             mPhoneStatusBar.setBouncerShowing(bouncerShowing);
+            mScrimController.setBouncerShowing(bouncerShowing);
         }
 
         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
deleted file mode 100644
index 049c5fc..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
+++ /dev/null
@@ -1,222 +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.content.Context;
-import android.content.res.TypedArray;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.Button;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.KeyButtonView;
-
-/**
- * A swipeable button for affordances on the lockscreen. This is used for the camera and phone
- * affordance.
- */
-public class SwipeAffordanceView extends KeyButtonView {
-
-    private static final int SWIPE_DIRECTION_START = 0;
-    private static final int SWIPE_DIRECTION_END = 1;
-
-    private static final int SWIPE_DIRECTION_LEFT = 0;
-    private static final int SWIPE_DIRECTION_RIGHT = 1;
-
-    private AffordanceListener mListener;
-    private int mScaledTouchSlop;
-    private float mDragDistance;
-    private int mResolvedSwipeDirection;
-    private int mSwipeDirection;
-
-    public SwipeAffordanceView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SwipeAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        TypedArray a = context.getTheme().obtainStyledAttributes(
-                attrs,
-                R.styleable.SwipeAffordanceView,
-                0, 0);
-        try {
-            mSwipeDirection = a.getInt(R.styleable.SwipeAffordanceView_swipeDirection, 0);
-        } finally {
-            a.recycle();
-        }
-    }
-
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        super.onRtlPropertiesChanged(layoutDirection);
-        if (!isLayoutRtl()) {
-            mResolvedSwipeDirection = mSwipeDirection;
-        } else {
-            mResolvedSwipeDirection = mSwipeDirection == SWIPE_DIRECTION_START
-                    ? SWIPE_DIRECTION_RIGHT
-                    : SWIPE_DIRECTION_LEFT;
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mDragDistance = getResources().getDimension(R.dimen.affordance_drag_distance);
-        mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
-    }
-
-    public void enableAccessibility(boolean touchExplorationEnabled) {
-
-        // Add a touch handler or accessibility click listener for camera button.
-        if (touchExplorationEnabled) {
-            setOnTouchListener(null);
-            setOnClickListener(mClickListener);
-        } else {
-            setOnTouchListener(mTouchListener);
-            setOnClickListener(null);
-        }
-    }
-
-    public void setAffordanceListener(AffordanceListener listener) {
-        mListener = listener;
-    }
-
-    private void onActionPerformed() {
-        if (mListener != null) {
-            mListener.onActionPerformed(this);
-        }
-    }
-
-    private void onUserActivity(long when) {
-        if (mListener != null) {
-            mListener.onUserActivity(when);
-        }
-    }
-
-    private final OnClickListener mClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            onActionPerformed();
-        }
-    };
-
-    private final OnTouchListener mTouchListener = new OnTouchListener() {
-        private float mStartX;
-        private boolean mTouchSlopReached;
-        private boolean mSkipCancelAnimation;
-
-        @Override
-        public boolean onTouch(final View view, MotionEvent event) {
-            float realX = event.getRawX();
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    mStartX = realX;
-                    mTouchSlopReached = false;
-                    mSkipCancelAnimation = false;
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                            ? realX > mStartX
-                            : realX < mStartX) {
-                        realX = mStartX;
-                    }
-                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                            ? realX < mStartX - mDragDistance
-                            : realX > mStartX + mDragDistance) {
-                        view.setPressed(true);
-                        onUserActivity(event.getEventTime());
-                    } else {
-                        view.setPressed(false);
-                    }
-                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                            ? realX < mStartX - mScaledTouchSlop
-                            : realX > mStartX + mScaledTouchSlop) {
-                        mTouchSlopReached = true;
-                    }
-                    view.setTranslationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                                    ? Math.max(realX - mStartX, -mDragDistance)
-                                    : Math.min(realX - mStartX, mDragDistance));
-                    break;
-                case MotionEvent.ACTION_UP:
-                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                            ? realX < mStartX - mDragDistance
-                            : realX > mStartX + mDragDistance) {
-                        onActionPerformed();
-                        view.animate().x(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                                ? -view.getWidth()
-                                : ((View) view.getParent()).getWidth() + view.getWidth())
-                                .setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
-                                new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        view.setTranslationX(0);
-                                    }
-                                });
-                        mSkipCancelAnimation = true;
-                    }
-                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                            ? realX < mStartX - mScaledTouchSlop
-                            : realX > mStartX + mScaledTouchSlop) {
-                        mTouchSlopReached = true;
-                    }
-                    if (!mTouchSlopReached) {
-                        mSkipCancelAnimation = true;
-                        view.animate().translationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
-                                ? -mDragDistance / 2
-                                : mDragDistance / 2).
-                                setInterpolator(new DecelerateInterpolator()).withEndAction(
-                                new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        view.animate().translationX(0).
-                                                setInterpolator(new AccelerateInterpolator());
-                                    }
-                                });
-                    }
-                case MotionEvent.ACTION_CANCEL:
-                    view.setPressed(false);
-                    if (!mSkipCancelAnimation) {
-                        view.animate().translationX(0)
-                                .setInterpolator(new AccelerateInterpolator(2f));
-                    }
-                    break;
-            }
-            return true;
-        }
-    };
-
-    public interface AffordanceListener {
-
-        /**
-         * Called when the view would like to report user activity.
-         *
-         * @param when The timestamp of the user activity in {@link SystemClock#uptimeMillis} time
-         *             base.
-         */
-        void onUserActivity(long when);
-
-        /**
-         * Called when the action of the affordance has been performed.
-         */
-        void onActionPerformed(SwipeAffordanceView view);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
new file mode 100644
index 0000000..bfd657b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -0,0 +1,107 @@
+/*
+ * 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 com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+
+import java.util.ArrayList;
+
+/**
+ * Caches whether the current unlock method is insecure, taking trust into account. This information
+ * might be a little bit out of date and should not be used for actual security decisions; it should
+ * be only used for visual indications.
+ */
+public class UnlockMethodCache {
+
+    private static UnlockMethodCache sInstance;
+
+    private final LockPatternUtils mLockPatternUtils;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final ArrayList<OnUnlockMethodChangedListener> mListeners = new ArrayList<>();
+    private boolean mMethodInsecure;
+
+    private UnlockMethodCache(Context ctx) {
+        mLockPatternUtils = new LockPatternUtils(ctx);
+        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(ctx);
+        KeyguardUpdateMonitor.getInstance(ctx).registerCallback(mCallback);
+        updateMethodSecure(true /* updateAlways */);
+    }
+
+    public static UnlockMethodCache getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new UnlockMethodCache(context);
+        }
+        return sInstance;
+    }
+
+    /**
+     * @return whether the current security method is secure, i. e. the bouncer will be shown
+     */
+    public boolean isMethodInsecure() {
+        return mMethodInsecure;
+    }
+
+    public void addListener(OnUnlockMethodChangedListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void removeListener(OnUnlockMethodChangedListener listener) {
+        mListeners.remove(listener);
+    }
+
+    private void updateMethodSecure(boolean updateAlways) {
+        int user = mLockPatternUtils.getCurrentUser();
+        boolean methodInsecure = !mLockPatternUtils.isSecure() ||
+                mKeyguardUpdateMonitor.getUserHasTrust(user);
+        boolean changed = methodInsecure != mMethodInsecure;
+        if (changed || updateAlways) {
+            mMethodInsecure = methodInsecure;
+            notifyListeners(mMethodInsecure);
+        }
+    }
+
+    private void notifyListeners(boolean secure) {
+        for (OnUnlockMethodChangedListener listener : mListeners) {
+            listener.onMethodSecureChanged(secure);
+        }
+    }
+
+    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onUserSwitchComplete(int userId) {
+            updateMethodSecure(false /* updateAlways */);
+        }
+
+        @Override
+        public void onTrustChanged(int userId) {
+            updateMethodSecure(false /* updateAlways */);
+        }
+
+        @Override
+        public void onScreenTurnedOn() {
+            updateMethodSecure(false /* updateAlways */);
+        }
+    };
+
+    public static interface OnUnlockMethodChangedListener {
+        void onMethodSecureChanged(boolean methodSecure);
+    }
+}
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 81e2cb3..9271e71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Outline;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -25,6 +26,7 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
 import com.android.systemui.ExpandHelper;
@@ -35,14 +37,17 @@
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.NotificationData;
 
-public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback {
+public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback,
+        ViewTreeObserver.OnComputeInternalInsetsListener {
     private static final String TAG = "HeadsUpNotificationView";
     private static final boolean DEBUG = false;
     private static final boolean SPEW = DEBUG;
 
     Rect mTmpRect = new Rect();
+    int[] mTmpTwoArray = new int[2];
 
     private final int mTouchSensitivityDelay;
+    private final float mMaxAlpha = 0.95f;
     private SwipeHelper mSwipeHelper;
     private EdgeSwipeHelper mEdgeSwipeHelper;
 
@@ -87,8 +92,9 @@
             }
             mContentHolder.setX(0);
             mContentHolder.setVisibility(View.VISIBLE);
-            mContentHolder.setAlpha(1f);
+            mContentHolder.setAlpha(mMaxAlpha);
             mContentHolder.addView(mHeadsUp.row);
+
             mSwipeHelper.snapChild(mContentHolder, 1f);
             mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
         }
@@ -99,32 +105,6 @@
         return mHeadsUp == null || mHeadsUp.notification.isClearable();
     }
 
-    public void setMargin(int notificationPanelMarginPx) {
-        if (SPEW) Log.v(TAG, "setMargin() " + notificationPanelMarginPx);
-        if (mContentHolder != null &&
-                mContentHolder.getLayoutParams() instanceof FrameLayout.LayoutParams) {
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentHolder.getLayoutParams();
-            lp.setMarginStart(notificationPanelMarginPx);
-            mContentHolder.setLayoutParams(lp);
-        }
-    }
-
-    // LinearLayout methods
-
-    @Override
-    public void onDraw(android.graphics.Canvas c) {
-        super.onDraw(c);
-        if (DEBUG) {
-            //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
-            //        + getMeasuredHeight() + "px");
-            c.save();
-            c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
-                    android.graphics.Region.Op.DIFFERENCE);
-            c.drawColor(0xFFcc00cc);
-            c.restore();
-        }
-    }
-
     // ViewGroup methods
 
     @Override
@@ -134,6 +114,7 @@
         float pagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
         float touchSlop = viewConfiguration.getScaledTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+        mSwipeHelper.setMaxAlpha(mMaxAlpha);
         mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop);
 
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
@@ -146,6 +127,8 @@
             // whoops, we're on already!
             setNotification(mHeadsUp);
         }
+
+        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
     @Override
@@ -163,6 +146,20 @@
     // View methods
 
     @Override
+    public void onDraw(android.graphics.Canvas c) {
+        super.onDraw(c);
+        if (DEBUG) {
+            //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
+            //        + getMeasuredHeight() + "px");
+            c.save();
+            c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
+                    android.graphics.Region.Op.DIFFERENCE);
+            c.drawColor(0xFFcc00cc);
+            c.restore();
+        }
+    }
+
+    @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (System.currentTimeMillis() < mStartTouchTime) {
             return false;
@@ -183,6 +180,14 @@
         mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        Outline o = new Outline();
+        o.setRect(0, 0, mContentHolder.getWidth(), mContentHolder.getHeight());
+        mContentHolder.setOutline(o);
+    }
+
     // ExpandHelper.Callback methods
 
     @Override
@@ -233,7 +238,7 @@
 
     @Override
     public void onDragCancelled(View v) {
-        mContentHolder.setAlpha(1f); // sometimes this isn't quite reset
+        mContentHolder.setAlpha(mMaxAlpha); // sometimes this isn't quite reset
     }
 
     @Override
@@ -250,6 +255,16 @@
         return mContentHolder;
     }
 
+    @Override
+    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+        mContentHolder.getLocationOnScreen(mTmpTwoArray);
+
+        info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+        info.touchableRegion.set(mTmpTwoArray[0], mTmpTwoArray[1],
+                mTmpTwoArray[0] + mContentHolder.getWidth(),
+                mTmpTwoArray[1] + mContentHolder.getHeight());
+    }
+
     private class EdgeSwipeHelper implements Gefingerpoken {
         private static final boolean DEBUG_EDGE_SWIPE = false;
         private final float mTouchSlop;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 718acc3..330b599 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -17,12 +17,9 @@
 package com.android.systemui.statusbar.policy;
 
 import android.animation.Animator;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.hardware.input.InputManager;
 import android.os.SystemClock;
@@ -34,9 +31,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SoundEffectConstants;
-import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 
@@ -46,25 +41,18 @@
     private static final String TAG = "StatusBar.KeyButtonView";
     private static final boolean DEBUG = false;
 
-    final float GLOW_MAX_SCALE_FACTOR = 1.8f;
     public static final float DEFAULT_QUIESCENT_ALPHA = 0.70f;
 
-    long mDownTime;
-    int mCode;
-    int mTouchSlop;
-    Drawable mGlowBG;
-    int mGlowWidth, mGlowHeight;
-    float mGlowAlpha = 0f, mGlowScale = 1f;
-    @ViewDebug.ExportedProperty(category = "drawing")
-    float mDrawingAlpha = 1f;
-    @ViewDebug.ExportedProperty(category = "drawing")
-    float mQuiescentAlpha = DEFAULT_QUIESCENT_ALPHA;
-    boolean mSupportsLongpress = true;
-    RectF mRect = new RectF();
-    AnimatorSet mPressedAnim;
-    Animator mAnimateToQuiescent = new ObjectAnimator();
+    private long mDownTime;
+    private int mCode;
+    private int mTouchSlop;
+    private float mDrawingAlpha = 1f;
+    private float mQuiescentAlpha = DEFAULT_QUIESCENT_ALPHA;
+    private boolean mSupportsLongpress = true;
+    private Animator mAnimateToQuiescent = new ObjectAnimator();
+    private Drawable mBackground;
 
-    Runnable mCheckLongPress = new Runnable() {
+    private final Runnable mCheckLongPress = new Runnable() {
         public void run() {
             if (isPressed()) {
                 // Log.d("KeyButtonView", "longpressed: " + this);
@@ -93,47 +81,27 @@
 
         mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
 
-        mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground);
-        setDrawingAlpha(mQuiescentAlpha);
-        if (mGlowBG != null) {
-            mGlowWidth = mGlowBG.getIntrinsicWidth();
-            mGlowHeight = mGlowBG.getIntrinsicHeight();
+        Drawable d = getBackground();
+        if (d != null) {
+            mBackground = d.mutate();
+            setBackground(mBackground);
         }
 
+        setDrawingAlpha(mQuiescentAlpha);
+
         a.recycle();
 
         setClickable(true);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     }
 
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mGlowBG != null) {
-            canvas.save();
-            final int w = getWidth();
-            final int h = getHeight();
-            final float aspect = (float)mGlowWidth / mGlowHeight;
-            final int drawW = (int)(h*aspect);
-            final int drawH = h;
-            final int margin = (drawW-w)/2;
-            canvas.scale(mGlowScale, mGlowScale, w*0.5f, h*0.5f);
-            mGlowBG.setBounds(-margin, 0, drawW-margin, drawH);
-            mGlowBG.setAlpha((int)(mDrawingAlpha * mGlowAlpha * 255));
-            mGlowBG.draw(canvas);
-            canvas.restore();
-            mRect.right = w;
-            mRect.bottom = h;
-        }
-        super.onDraw(canvas);
-    }
-
     public void setQuiescentAlpha(float alpha, boolean animate) {
         mAnimateToQuiescent.cancel();
         alpha = Math.min(Math.max(alpha, 0), 1);
         if (alpha == mQuiescentAlpha && alpha == mDrawingAlpha) return;
         mQuiescentAlpha = alpha;
         if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha);
-        if (mGlowBG != null && animate) {
+        if (mBackground != null && animate) {
             mAnimateToQuiescent = animateToQuiescent();
             mAnimateToQuiescent.start();
         } else {
@@ -154,87 +122,35 @@
     }
 
     public void setDrawingAlpha(float x) {
-        // Calling setAlpha(int), which is an ImageView-specific
-        // method that's different from setAlpha(float). This sets
-        // the alpha on this ImageView's drawable directly
-        setAlpha((int) (x * 255));
+        setImageAlpha((int) (x * 255));
+        if (mBackground != null) {
+            mBackground.setAlpha((int)(x * 255));
+        }
         mDrawingAlpha = x;
     }
 
-    public float getGlowAlpha() {
-        if (mGlowBG == null) return 0;
-        return mGlowAlpha;
-    }
-
-    public void setGlowAlpha(float x) {
-        if (mGlowBG == null) return;
-        mGlowAlpha = x;
-        invalidate();
-    }
-
-    public float getGlowScale() {
-        if (mGlowBG == null) return 0;
-        return mGlowScale;
-    }
-
-    public void setGlowScale(float x) {
-        if (mGlowBG == null) return;
-        mGlowScale = x;
-        final float w = getWidth();
-        final float h = getHeight();
-        if (GLOW_MAX_SCALE_FACTOR <= 1.0f) {
-            // this only works if we know the glow will never leave our bounds
-            invalidate();
-        } else {
-            final float rx = (w * (GLOW_MAX_SCALE_FACTOR - 1.0f)) / 2.0f + 1.0f;
-            final float ry = (h * (GLOW_MAX_SCALE_FACTOR - 1.0f)) / 2.0f + 1.0f;
-            com.android.systemui.SwipeHelper.invalidateGlobalRegion(
-                    this,
-                    new RectF(getLeft() - rx,
-                              getTop() - ry,
-                              getRight() + rx,
-                              getBottom() + ry));
-
-            // also invalidate our immediate parent to help avoid situations where nearby glows
-            // interfere
-            ((View)getParent()).invalidate();
-        }
-    }
-
     public void setPressed(boolean pressed) {
-        if (mGlowBG != null) {
+        if (mBackground != null) {
             if (pressed != isPressed()) {
-                if (mPressedAnim != null && mPressedAnim.isRunning()) {
-                    mPressedAnim.cancel();
-                }
-                final AnimatorSet as = mPressedAnim = new AnimatorSet();
                 if (pressed) {
-                    if (mGlowScale < GLOW_MAX_SCALE_FACTOR)
-                        mGlowScale = GLOW_MAX_SCALE_FACTOR;
-                    if (mGlowAlpha < mQuiescentAlpha)
-                        mGlowAlpha = mQuiescentAlpha;
                     setDrawingAlpha(1f);
-                    as.playTogether(
-                        ObjectAnimator.ofFloat(this, "glowAlpha", 1f),
-                        ObjectAnimator.ofFloat(this, "glowScale", GLOW_MAX_SCALE_FACTOR)
-                    );
-                    as.setDuration(50);
                 } else {
                     mAnimateToQuiescent.cancel();
                     mAnimateToQuiescent = animateToQuiescent();
-                    as.playTogether(
-                        ObjectAnimator.ofFloat(this, "glowAlpha", 0f),
-                        ObjectAnimator.ofFloat(this, "glowScale", 1f),
-                        mAnimateToQuiescent
-                    );
-                    as.setDuration(500);
+                    mAnimateToQuiescent.setDuration(500);
+                    mAnimateToQuiescent.start();
                 }
-                as.start();
             }
         }
         super.setPressed(pressed);
     }
 
+    private void setHotspot(float x, float y) {
+        if (mBackground != null) {
+            mBackground.setHotspot(x, y);
+        }
+    }
+
     public boolean onTouchEvent(MotionEvent ev) {
         final int action = ev.getAction();
         int x, y;
@@ -254,6 +170,7 @@
                     removeCallbacks(mCheckLongPress);
                     postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                 }
+                setHotspot(ev.getX(), ev.getY());
                 break;
             case MotionEvent.ACTION_MOVE:
                 x = (int)ev.getX();
@@ -262,6 +179,7 @@
                         && x < getWidth() + mTouchSlop
                         && y >= -mTouchSlop
                         && y < getHeight() + mTouchSlop);
+                setHotspot(ev.getX(), ev.getY());
                 break;
             case MotionEvent.ACTION_CANCEL:
                 setPressed(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index 173af40..3ce6905 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -166,7 +166,7 @@
                 if (rawAvatar != null) {
                     avatar = new BitmapDrawable(mContext.getResources(), circularClip(rawAvatar));
                 } else {
-                    avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
+                    avatar = mContext.getResources().getDrawable(R.drawable.ic_account_circle);
                     mUseDefaultAvatar = true;
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 5e2d06b..cf56fa57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -27,6 +27,7 @@
     boolean animateZ;
     boolean animateScale;
     boolean animateHeight;
+    boolean animateTopInset;
     boolean animateDimmed;
     boolean hasDelays;
 
@@ -60,6 +61,11 @@
         return this;
     }
 
+    public AnimationFilter animateTopInset() {
+        animateTopInset = true;
+        return this;
+    }
+
     public AnimationFilter animateDimmed() {
         animateDimmed = true;
         return this;
@@ -84,6 +90,7 @@
         animateZ |= filter.animateZ;
         animateScale |= filter.animateScale;
         animateHeight |= filter.animateHeight;
+        animateTopInset |= filter.animateTopInset;
         animateDimmed |= filter.animateDimmed;
         hasDelays |= filter.hasDelays;
     }
@@ -94,6 +101,7 @@
         animateZ = false;
         animateScale = false;
         animateHeight = false;
+        animateTopInset = false;
         animateDimmed = false;
         hasDelays = false;
     }
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 079b184..58176b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1599,6 +1599,7 @@
                 new AnimationFilter()
                         .animateAlpha()
                         .animateHeight()
+                        .animateTopInset()
                         .animateY()
                         .animateZ()
                         .hasDelays(),
@@ -1607,6 +1608,7 @@
                 new AnimationFilter()
                         .animateAlpha()
                         .animateHeight()
+                        .animateTopInset()
                         .animateY()
                         .animateZ()
                         .hasDelays(),
@@ -1615,6 +1617,7 @@
                 new AnimationFilter()
                         .animateAlpha()
                         .animateHeight()
+                        .animateTopInset()
                         .animateY()
                         .animateZ()
                         .hasDelays(),
@@ -1623,6 +1626,7 @@
                 new AnimationFilter()
                         .animateAlpha()
                         .animateHeight()
+                        .animateTopInset()
                         .animateY()
                         .animateDimmed()
                         .animateScale()
@@ -1651,6 +1655,7 @@
                 new AnimationFilter()
                         .animateAlpha()
                         .animateHeight()
+                        .animateTopInset()
                         .animateY()
                         .animateZ()
         };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index bd2541a..2b52c7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -49,6 +49,7 @@
     private int mBottomStackPeekSize;
     private int mZDistanceBetweenElements;
     private int mZBasicHeight;
+    private int mRoundedRectCornerRadius;
 
     private StackIndentationFunctor mTopStackIndentationFunctor;
     private StackIndentationFunctor mBottomStackIndentationFunctor;
@@ -111,6 +112,8 @@
         mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
         mBottomStackSlowDownLength = context.getResources()
                 .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
+        mRoundedRectCornerRadius = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_quantum_rounded_rect_radius);
     }
 
 
@@ -146,6 +149,67 @@
 
         handleDraggedViews(ambientState, resultState, algorithmState);
         updateDimmedActivated(ambientState, resultState, algorithmState);
+        updateClipping(resultState, algorithmState);
+    }
+
+    private void updateClipping(StackScrollState resultState,
+            StackScrollAlgorithmState algorithmState) {
+        float previousNotificationEnd = 0;
+        float previousNotificationStart = 0;
+        boolean previousNotificationIsSwiped = false;
+        int childCount = algorithmState.visibleChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            ExpandableView child = algorithmState.visibleChildren.get(i);
+            StackScrollState.ViewState state = resultState.getViewStateForView(child);
+            float newYTranslation = state.yTranslation;
+            int newHeight = state.height;
+            // apply clipping and shadow
+            float newNotificationEnd = newYTranslation + newHeight;
+
+            // In the unlocked shade we have to clip a little bit higher because of the rounded
+            // corners of the notifications.
+            float clippingCorrection = state.dimmed ? 0 : mRoundedRectCornerRadius;
+
+            // When the previous notification is swiped, we don't clip the content to the
+            // bottom of it.
+            float clipHeight = previousNotificationIsSwiped
+                    ? newHeight
+                    : newNotificationEnd - (previousNotificationEnd - clippingCorrection);
+
+            updateChildClippingAndBackground(state, newHeight, clipHeight,
+                    (int) (newHeight - (previousNotificationStart - newYTranslation)));
+
+            if (!child.isTransparent()) {
+                // Only update the previous values if we are not transparent,
+                // otherwise we would clip to a transparent view.
+                previousNotificationStart = newYTranslation + child.getClipTopAmount();
+                previousNotificationEnd = newNotificationEnd;
+                previousNotificationIsSwiped = child.getTranslationX() != 0;
+            }
+        }
+    }
+
+    /**
+     * Updates the shadow outline and the clipping for a view.
+     *
+     * @param state the viewState to update
+     * @param realHeight the currently applied height of the view
+     * @param clipHeight the desired clip height, the rest of the view will be clipped from the top
+     * @param backgroundHeight the desired background height. The shadows of the view will be
+     *                         based on this height and the content will be clipped from the top
+     */
+    private void updateChildClippingAndBackground(StackScrollState.ViewState state, int realHeight,
+            float clipHeight, int backgroundHeight) {
+        if (realHeight > clipHeight) {
+            state.topOverLap = (int) (realHeight - clipHeight);
+        } else {
+            state.topOverLap = 0;
+        }
+        if (realHeight > backgroundHeight) {
+            state.clipTopAmount = (realHeight - backgroundHeight);
+        } else {
+            state.clipTopAmount = 0;
+        }
     }
 
     /**
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 ae2acab..94cb16d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.stack;
 
-import android.graphics.Outline;
 import android.graphics.Rect;
 import android.util.Log;
 import android.view.View;
@@ -80,9 +79,6 @@
      */
     public void apply() {
         int numChildren = mHostView.getChildCount();
-        float previousNotificationEnd = 0;
-        float previousNotificationStart = 0;
-        boolean previousNotificationIsSwiped = false;
         for (int i = 0; i < numChildren; i++) {
             ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
             ViewState state = mStateMap.get(child);
@@ -152,35 +148,41 @@
                 // apply dimming
                 child.setDimmed(state.dimmed, false /* animate */);
 
-                // apply clipping and shadow
-                float newNotificationEnd = newYTranslation + newHeight;
+                float oldClipTopAmount = child.getClipTopAmount();
+                if (oldClipTopAmount != state.clipTopAmount) {
+                    child.setClipTopAmount(state.clipTopAmount);
+                }
 
-                // When the previous notification is swiped, we don't clip the content to the
-                // bottom of it.
-                float clipHeight = previousNotificationIsSwiped
-                        ? newHeight
-                        : newNotificationEnd - (previousNotificationEnd);
-
-                updateChildClippingAndBackground(child, newHeight,
-                        clipHeight,
-                        (int) (newHeight - (previousNotificationStart - newYTranslation)));
-
-                if (!child.isTransparent()) {
-                    // Only update the previous values if we are not transparent,
-                    // otherwise we would clip to a transparent view.
-                    previousNotificationStart = newYTranslation + child.getClipTopAmount();
-                    previousNotificationEnd = newNotificationEnd;
-                    previousNotificationIsSwiped = child.getTranslationX() != 0;
+                if (state.topOverLap != 0) {
+                    updateChildClip(child, newHeight, state.topOverLap);
+                } else {
+                    child.setClipBounds(null);
                 }
 
                 if(child instanceof SpeedBumpView) {
-                    performSpeedBumpAnimation(i, (SpeedBumpView) child, newNotificationEnd,
+                    float speedBumpEnd = newYTranslation + newHeight;
+                    performSpeedBumpAnimation(i, (SpeedBumpView) child, speedBumpEnd,
                             newYTranslation);
                 }
             }
         }
     }
 
+    /**
+     * Updates the clipping of a view
+     *
+     * @param child the view to update
+     * @param height the currently applied height of the view
+     * @param clipInset how much should this view be clipped from the top
+     */
+    private void updateChildClip(View child, int height, int clipInset) {
+        mClipRect.set(0,
+                clipInset,
+                child.getWidth(),
+                height);
+        child.setClipBounds(mClipRect);
+    }
+
     private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
             float speedBumpStart) {
         View nextChild = getNextChildNotGone(i);
@@ -209,45 +211,6 @@
         return null;
     }
 
-    /**
-     * Updates the shadow outline and the clipping for a view.
-     *
-     * @param child the view to update
-     * @param realHeight the currently applied height of the view
-     * @param clipHeight the desired clip height, the rest of the view will be clipped from the top
-     * @param backgroundHeight the desired background height. The shadows of the view will be
-     *                         based on this height and the content will be clipped from the top
-     */
-    private void updateChildClippingAndBackground(ExpandableView child, int realHeight,
-            float clipHeight, int backgroundHeight) {
-        if (realHeight > clipHeight) {
-            updateChildClip(child, realHeight, clipHeight);
-        } else {
-            child.setClipBounds(null);
-        }
-        if (realHeight > backgroundHeight) {
-            child.setClipTopAmount(realHeight - backgroundHeight);
-        } else {
-            child.setClipTopAmount(0);
-        }
-    }
-
-    /**
-     * Updates the clipping of a view
-     *
-     * @param child the view to update
-     * @param height the currently applied height of the view
-     * @param clipHeight the desired clip height, the rest of the view will be clipped from the top
-     */
-    private void updateChildClip(View child, int height, float clipHeight) {
-        int clipInset = (int) (height - clipHeight);
-        mClipRect.set(0,
-                clipInset,
-                child.getWidth(),
-                height);
-        child.setClipBounds(mClipRect);
-    }
-
     public static class ViewState {
 
         // These are flags such that we can create masks for filtering.
@@ -269,6 +232,18 @@
         boolean dimmed;
 
         /**
+         * The amount which the view should be clipped from the top. This is calculated to
+         * perceive consistent shadows.
+         */
+        int clipTopAmount;
+
+        /**
+         * How much does the child overlap with the previous view on the top? Can be used for
+         * a clipping optimization
+         */
+        int topOverLap;
+
+        /**
          * The index of the view, only accounting for views not equal to GONE
          */
         int notGoneIndex;
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 045a99d..f41ab3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -133,10 +133,11 @@
         boolean scaleChanging = child.getScaleX() != viewState.scale;
         boolean alphaChanging = alpha != child.getAlpha();
         boolean heightChanging = viewState.height != child.getActualHeight();
+        boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
         boolean wasAdded = mNewAddChildren.contains(child);
         boolean hasDelays = mAnimationFilter.hasDelays;
         boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
-                alphaChanging || heightChanging;
+                alphaChanging || heightChanging || topInsetChanging;
         long delay = 0;
         if (hasDelays && isDelayRelevant || wasAdded) {
             delay = calculateChildAnimationDelay(viewState, finalState);
@@ -167,6 +168,11 @@
             startHeightAnimation(child, viewState, delay);
         }
 
+        // start top inset animation
+        if (topInsetChanging) {
+            startInsetAnimation(child, viewState, delay);
+        }
+
         // start dimmed animation
         child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
 
@@ -280,6 +286,64 @@
         child.setTag(TAG_END_HEIGHT, newEndValue);
     }
 
+    private void startInsetAnimation(final ExpandableView child,
+            StackScrollState.ViewState viewState, long delay) {
+        Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
+        Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
+        int newEndValue = viewState.clipTopAmount;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET);
+        if (!mAnimationFilter.animateTopInset) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                int relativeDiff = newEndValue - previousEndValue;
+                int newStartValue = previousStartValue + relativeDiff;
+                values[0].setIntValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TOP_INSET, newStartValue);
+                child.setTag(TAG_END_TOP_INSET, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setClipTopAmount(newEndValue);
+                return;
+            }
+        }
+
+        ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                child.setClipTopAmount((int) animation.getAnimatedValue());
+            }
+        });
+        animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+        animator.setDuration(newDuration);
+        if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+            animator.setStartDelay(delay);
+        }
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_TOP_INSET, null);
+                child.setTag(TAG_START_TOP_INSET, null);
+                child.setTag(TAG_END_TOP_INSET, null);
+            }
+        });
+        startAnimator(animator);
+        child.setTag(TAG_ANIMATOR_TOP_INSET, animator);
+        child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount());
+        child.setTag(TAG_END_TOP_INSET, newEndValue);
+    }
+
     private void startAlphaAnimation(final ExpandableView child,
             final StackScrollState.ViewState viewState, long delay) {
         Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
@@ -315,14 +379,13 @@
                 child.getAlpha(), newEndValue);
         animator.setInterpolator(mFastOutSlowInInterpolator);
         // Handle layer type
-        final int currentLayerType = child.getLayerType();
         child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         animator.addListener(new AnimatorListenerAdapter() {
             public boolean mWasCancelled;
 
             @Override
             public void onAnimationEnd(Animator animation) {
-                child.setLayerType(currentLayerType, null);
+                child.setLayerType(View.LAYER_TYPE_NONE, null);
                 if (newEndValue == 0 && !mWasCancelled) {
                     child.setVisibility(View.INVISIBLE);
                 }
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 25147b4..c2bd1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,12 +17,12 @@
 package com.android.systemui.statusbar.tv;
 
 import android.os.IBinder;
+import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.StatusBarNotification;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 
-import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.statusbar.BaseStatusBar;
 
@@ -50,7 +50,7 @@
     }
 
     @Override
-    public void addNotificationInternal(StatusBarNotification notification) {
+    public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
     }
 
     @Override
@@ -58,7 +58,7 @@
     }
 
     @Override
-    protected void removeNotificationInternal(String key) {
+    protected void removeNotificationInternal(String key, Ranking ranking) {
     }
 
     @Override
@@ -117,7 +117,7 @@
     }
 
     @Override
-    protected void updateNotificationIcons() {
+    protected void updateNotifications() {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
new file mode 100644
index 0000000..5ee89253
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
@@ -0,0 +1,24 @@
+/*
+ * 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.volume;
+
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+public interface VolumeComponent {
+    ZenModeController getZenController();
+    void setVolumePanel(VolumePanel panel);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 8657e07..06f4c2e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -16,14 +16,12 @@
 
 package com.android.systemui.volume;
 
-import com.android.internal.R;
-
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.content.DialogInterface.OnDismissListener;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
@@ -42,6 +40,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -49,6 +48,9 @@
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
+import com.android.internal.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
 import java.util.HashMap;
 
 /**
@@ -57,7 +59,6 @@
  * @hide
  */
 public class VolumePanel extends Handler {
-    private static final String TAG = VolumePanel.class.getSimpleName();
     private static boolean LOGD = false;
 
     private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
@@ -88,33 +89,48 @@
     private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9;
     private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
     private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
+    private static final int MSG_LAYOUT_DIRECTION = 12;
+    private static final int MSG_ZEN_MODE_CHANGED = 13;
 
     // Pseudo stream type for master volume
     private static final int STREAM_MASTER = -100;
     // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC
 
+    private final String mTag;
     protected final Context mContext;
     private final AudioManager mAudioManager;
+    private final ZenModeController mZenController;
     private boolean mRingIsSilent;
-    private boolean mShowCombinedVolumes;
     private boolean mVoiceCapable;
+    private boolean mZenModeCapable;
 
     // True if we want to play tones on the system stream when the master stream is specified.
     private final boolean mPlayMasterStreamTones;
 
-    /** Dialog containing all the sliders */
-    private final Dialog mDialog;
-    /** Dialog's content view */
+
+    /** Volume panel content view */
     private final View mView;
+    /** Dialog hosting the panel, if not embedded */
+    private final Dialog mDialog;
+    /** Parent view hosting the panel, if embedded */
+    private final ViewGroup mParent;
 
     /** The visible portion of the volume overlay */
     private final ViewGroup mPanel;
-    /** Contains the sliders and their touchable icons */
-    private final ViewGroup mSliderGroup;
-    /** The button that expands the dialog to show all sliders */
-    private final View mMoreButton;
-    /** Dummy divider icon that needs to vanish with the more button */
-    private final View mDivider;
+    /** Contains the slider and its touchable icons */
+    private final ViewGroup mSliderPanel;
+    /** The button that expands the dialog to show the zen panel */
+    private final ImageView mExpandButton;
+    /** Dummy divider icon that needs to vanish with the expand button */
+    private final View mExpandDivider;
+    /** The zen mode configuration panel view stub */
+    private final ViewStub mZenPanelStub;
+    /** The zen mode configuration panel view, once inflated */
+    private ZenModePanel mZenPanel;
+    /** Dummy divider icon that needs to vanish with the zen panel */
+    private final View mZenPanelDivider;
+
+    private ZenModePanel.Callback mZenPanelCallback;
 
     /** Currently active stream that shows up at the top of the list of sliders */
     private int mActiveStreamType = -1;
@@ -129,8 +145,8 @@
                 false),
         RingerStream(AudioManager.STREAM_RING,
                 R.string.volume_icon_description_ringer,
-                R.drawable.ic_audio_ring_notif,
-                R.drawable.ic_audio_ring_notif_mute,
+                com.android.systemui.R.drawable.ic_ringer_audible,
+                com.android.systemui.R.drawable.ic_ringer_silent,
                 false),
         VoiceStream(AudioManager.STREAM_VOICE_CALL,
                 R.string.volume_icon_description_incall,
@@ -149,8 +165,8 @@
                 true),
         NotificationStream(AudioManager.STREAM_NOTIFICATION,
                 R.string.volume_icon_description_notification,
-                R.drawable.ic_audio_notification,
-                R.drawable.ic_audio_notification_mute,
+                com.android.systemui.R.drawable.ic_ringer_audible,
+                com.android.systemui.R.drawable.ic_ringer_silent,
                 true),
         // for now, use media resources for master volume
         MasterStream(STREAM_MASTER,
@@ -245,8 +261,11 @@
     }
 
 
-    public VolumePanel(Context context) {
+    public VolumePanel(Context context, ViewGroup parent, ZenModeController zenController) {
+        mTag = String.format("VolumePanel%s.%08x", parent == null ? "Dialog" : "", hashCode());
         mContext = context;
+        mParent = parent;
+        mZenController = zenController;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         // For now, only show master volume if master volume is supported
@@ -258,74 +277,81 @@
                 streamRes.show = (streamRes.streamType == STREAM_MASTER);
             }
         }
-
-        mDialog = new Dialog(context) {
-            @Override
-            public boolean onTouchEvent(MotionEvent event) {
-                if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
-                        sConfirmSafeVolumeDialog == null) {
-                    forceTimeout();
-                    return true;
+        if (LOGD) Log.d(mTag, String.format("new VolumePanel hasParent=%s", parent != null));
+        final int layoutId = com.android.systemui.R.layout.volume_panel;
+        if (parent == null) {
+            // dialog mode
+            mDialog = new Dialog(context) {
+                @Override
+                public boolean onTouchEvent(MotionEvent event) {
+                    if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
+                            sConfirmSafeVolumeDialog == null) {
+                        forceTimeout();
+                        return true;
+                    }
+                    return false;
                 }
-                return false;
-            }
-        };
+            };
 
-        // Change some window properties
-        final Window window = mDialog.getWindow();
-        final LayoutParams lp = window.getAttributes();
-        lp.token = null;
-        // Offset from the top
-        lp.y = res.getDimensionPixelOffset(R.dimen.volume_panel_top);
-        lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
-        lp.windowAnimations = R.style.Animation_VolumePanel;
-        window.setAttributes(lp);
-        window.setGravity(Gravity.TOP);
-        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-        window.requestFeature(Window.FEATURE_NO_TITLE);
-        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
-                | LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+            // Change some window properties
+            final Window window = mDialog.getWindow();
+            final LayoutParams lp = window.getAttributes();
+            lp.token = null;
+            // Offset from the top
+            lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
+            lp.width = res.getDimensionPixelSize(com.android.systemui.R.dimen.volume_panel_width);
+            lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
+            lp.windowAnimations = R.style.Animation_VolumePanel;
+            window.setBackgroundDrawableResource(com.android.systemui.R.drawable.qs_panel_background);
+            window.setAttributes(lp);
+            window.setGravity(Gravity.TOP);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+            window.requestFeature(Window.FEATURE_NO_TITLE);
+            window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
+                    | LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+            mDialog.setCanceledOnTouchOutside(true);
+            mDialog.setContentView(layoutId);
+            mDialog.setOnDismissListener(new OnDismissListener() {
+                @Override
+                public void onDismiss(DialogInterface dialog) {
+                    mActiveStreamType = -1;
+                    mAudioManager.forceVolumeControlStream(mActiveStreamType);
+                }
+            });
 
-        mDialog.setCanceledOnTouchOutside(true);
-        mDialog.setContentView(R.layout.volume_adjust);
-        mDialog.setOnDismissListener(new OnDismissListener() {
-            @Override
-            public void onDismiss(DialogInterface dialog) {
-                mActiveStreamType = -1;
-                mAudioManager.forceVolumeControlStream(mActiveStreamType);
-            }
-        });
+            mDialog.create();
 
-        mDialog.create();
+            mView = window.findViewById(R.id.content);
+            mView.setOnTouchListener(new View.OnTouchListener() {
+                @Override
+                public boolean onTouch(View v, MotionEvent event) {
+                    resetTimeout();
+                    return false;
+                }
+            });
 
-        mView = window.findViewById(R.id.content);
-        mView.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                resetTimeout();
-                return false;
-            }
-        });
-
-        mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
-        mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
-        mMoreButton = mView.findViewById(R.id.expand_button);
-        mDivider = mView.findViewById(R.id.expand_button_divider);
+        } else {
+            // embedded mode
+            mDialog = null;
+            mView = LayoutInflater.from(mContext).inflate(layoutId, parent, true);
+        }
+        mPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.visible_panel);
+        mSliderPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.slider_panel);
+        mExpandButton = (ImageView) mView.findViewById(com.android.systemui.R.id.expand_button);
+        mExpandDivider = mView.findViewById(com.android.systemui.R.id.expand_button_divider);
+        mZenPanelStub = (ViewStub)mView.findViewById(com.android.systemui.R.id.zen_panel_stub);
+        mZenPanelDivider = mView.findViewById(com.android.systemui.R.id.zen_panel_divider);
 
         mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
 
-        // If we don't want to show multiple volumes, hide the settings button
-        // and divider.
-        mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
-        if (!mShowCombinedVolumes) {
-            mMoreButton.setVisibility(View.GONE);
-            mDivider.setVisibility(View.GONE);
-        } else {
-            mMoreButton.setOnClickListener(mClickListener);
-        }
+        mZenModeCapable = !useMasterVolume && mZenController != null;
+        mZenPanelDivider.setVisibility(View.GONE);
+        mExpandButton.setOnClickListener(mClickListener);
+        updateZenMode(mZenController == null ? false : mZenController.isZen());
+        mZenController.addCallback(mZenCallback);
 
         final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
         final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
@@ -334,7 +360,7 @@
         listenToRingerMode();
     }
 
-    public void setLayoutDirection(int layoutDirection) {
+    private void setLayoutDirection(int layoutDirection) {
         mPanel.setLayoutDirection(layoutDirection);
         updateStates();
     }
@@ -406,21 +432,19 @@
             StreamResources streamRes = STREAMS[i];
 
             final int streamType = streamRes.streamType;
-            if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
-                streamRes = StreamResources.RingerStream;
-            }
 
             final StreamControl sc = new StreamControl();
             sc.streamType = streamType;
-            sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
+            sc.group = (ViewGroup) inflater.inflate(
+                    com.android.systemui.R.layout.volume_panel_item, null);
             sc.group.setTag(sc);
-            sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
+            sc.icon = (ImageView) sc.group.findViewById(com.android.systemui.R.id.stream_icon);
             sc.icon.setTag(sc);
             sc.icon.setContentDescription(res.getString(streamRes.descRes));
             sc.iconRes = streamRes.iconRes;
             sc.iconMuteRes = streamRes.iconMuteRes;
             sc.icon.setImageResource(sc.iconRes);
-            sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
+            sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar);
             final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
                     streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
             sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
@@ -431,34 +455,18 @@
     }
 
     private void reorderSliders(int activeStreamType) {
-        mSliderGroup.removeAllViews();
+        mSliderPanel.removeAllViews();
 
         final StreamControl active = mStreamControls.get(activeStreamType);
         if (active == null) {
             Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
             mActiveStreamType = -1;
         } else {
-            mSliderGroup.addView(active.group);
+            mSliderPanel.addView(active.group);
             mActiveStreamType = activeStreamType;
             active.group.setVisibility(View.VISIBLE);
             updateSlider(active);
-        }
-
-        addOtherVolumes();
-    }
-
-    private void addOtherVolumes() {
-        if (!mShowCombinedVolumes) return;
-
-        for (int i = 0; i < STREAMS.length; i++) {
-            // Skip the phone specific ones and the active one
-            final int streamType = STREAMS[i].streamType;
-            if (!STREAMS[i].show || streamType == mActiveStreamType) {
-                continue;
-            }
-            StreamControl sc = mStreamControls.get(streamType);
-            mSliderGroup.addView(sc.group);
-            updateSlider(sc);
+            updateZenMode(mZenController == null ? false : mZenController.isZen());
         }
     }
 
@@ -472,7 +480,7 @@
         if (((sc.streamType == AudioManager.STREAM_RING) ||
                 (sc.streamType == AudioManager.STREAM_NOTIFICATION)) &&
                 mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
-            sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
+            sc.icon.setImageResource(com.android.systemui.R.drawable.ic_ringer_vibrate);
         }
         if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
             // never disable touch interactions for remote playback, the muting is not tied to
@@ -486,32 +494,70 @@
         }
     }
 
+    public void setZenModePanelCallback(ZenModePanel.Callback callback) {
+        mZenPanelCallback = callback;
+    }
+
     private void expand() {
-        final int count = mSliderGroup.getChildCount();
-        for (int i = 0; i < count; i++) {
-            mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
+        if (LOGD) Log.d(mTag, "expand mZenPanel=" + mZenPanel);
+        if (mZenPanel == null) {
+            mZenPanel = (ZenModePanel) mZenPanelStub.inflate();
+            mZenPanel.init(mZenController);
+            mZenPanel.setCallback(new ZenModePanel.Callback() {
+                @Override
+                public void onMoreSettings() {
+                    if (mZenPanelCallback != null) {
+                        mZenPanelCallback.onMoreSettings();
+                    }
+                }
+
+                @Override
+                public void onInteraction() {
+                    if (mZenPanelCallback != null) {
+                        mZenPanelCallback.onInteraction();
+                    }
+                }
+            });
         }
-        mMoreButton.setVisibility(View.INVISIBLE);
-        mDivider.setVisibility(View.INVISIBLE);
+        mZenPanel.setVisibility(View.VISIBLE);
+        mZenPanelDivider.setVisibility(View.VISIBLE);
     }
 
     private void collapse() {
-        mMoreButton.setVisibility(View.VISIBLE);
-        mDivider.setVisibility(View.VISIBLE);
-        final int count = mSliderGroup.getChildCount();
-        for (int i = 1; i < count; i++) {
-            mSliderGroup.getChildAt(i).setVisibility(View.GONE);
+        if (LOGD) Log.d(mTag, "collapse mZenPanel=" + mZenPanel);
+        if (mZenPanel != null) {
+            mZenPanel.setVisibility(View.GONE);
         }
+        mZenPanelDivider.setVisibility(View.GONE);
     }
 
     public void updateStates() {
-        final int count = mSliderGroup.getChildCount();
+        final int count = mSliderPanel.getChildCount();
         for (int i = 0; i < count; i++) {
-            StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
+            StreamControl sc = (StreamControl) mSliderPanel.getChildAt(i).getTag();
             updateSlider(sc);
         }
     }
 
+    private void updateZenMode(boolean zen) {
+        if (mZenModeCapable) {
+            final boolean show = mActiveStreamType == AudioManager.STREAM_NOTIFICATION
+                    || mActiveStreamType == AudioManager.STREAM_RING;
+            mExpandButton.setVisibility(show ? View.VISIBLE : View.GONE);
+            mExpandDivider.setVisibility(show ? View.VISIBLE : View.GONE);
+            mExpandButton.setImageResource(zen ? com.android.systemui.R.drawable.ic_vol_zen_on
+                    : com.android.systemui.R.drawable.ic_vol_zen_off);
+        } else {
+            mExpandButton.setVisibility(View.GONE);
+            mExpandDivider.setVisibility(View.GONE);
+        }
+    }
+
+    public void postZenModeChanged(boolean zen) {
+        removeMessages(MSG_ZEN_MODE_CHANGED);
+        obtainMessage(MSG_ZEN_MODE_CHANGED, zen ? 1 : 0).sendToTarget();
+    }
+
     public void postVolumeChanged(int streamType, int flags) {
         if (hasMessages(MSG_VOLUME_CHANGED)) return;
         synchronized (this) {
@@ -582,8 +628,12 @@
     }
 
     public void postDismiss() {
-        removeMessages(MSG_TIMEOUT);
-        sendEmptyMessage(MSG_TIMEOUT);
+        forceTimeout();
+    }
+
+    public void postLayoutDirection(int layoutDirection) {
+        removeMessages(MSG_LAYOUT_DIRECTION);
+        obtainMessage(MSG_LAYOUT_DIRECTION, layoutDirection).sendToTarget();
     }
 
     /**
@@ -593,7 +643,7 @@
      */
     protected void onVolumeChanged(int streamType, int flags) {
 
-        if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
+        if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
 
         if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
             synchronized (this) {
@@ -622,7 +672,7 @@
 
     protected void onMuteChanged(int streamType, int flags) {
 
-        if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
+        if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
 
         StreamControl sc = mStreamControls.get(streamType);
         if (sc != null) {
@@ -638,7 +688,7 @@
         mRingIsSilent = false;
 
         if (LOGD) {
-            Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
+            Log.d(mTag, "onShowVolumeChanged(streamType: " + streamType
                     + ", flags: " + flags + "), index: " + index);
         }
 
@@ -707,7 +757,7 @@
             }
 
             case AudioService.STREAM_REMOTE_MUSIC: {
-                if (LOGD) { Log.d(TAG, "showing remote volume "+index+" over "+ max); }
+                if (LOGD) { Log.d(mTag, "showing remote volume "+index+" over "+ max); }
                 break;
             }
         }
@@ -730,16 +780,18 @@
             }
         }
 
-        if (!mDialog.isShowing()) {
+        if (!isShowing()) {
             int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
             // when the stream is for remote playback, use -1 to reset the stream type evaluation
             mAudioManager.forceVolumeControlStream(stream);
 
             // Showing dialog - use collapsed state
-            if (mShowCombinedVolumes) {
+            if (mZenModeCapable) {
                 collapse();
             }
-            mDialog.show();
+            if (mDialog != null) {
+                mDialog.show();
+            }
         }
 
         // Do a little vibrate if applicable (only when going into vibrate mode)
@@ -751,6 +803,10 @@
         }
     }
 
+    private boolean isShowing() {
+        return mDialog != null ? mDialog.isShowing() : mParent.isAttachedToWindow();
+    }
+
     protected void onPlaySound(int streamType, int flags) {
 
         if (hasMessages(MSG_STOP_SOUNDS)) {
@@ -795,9 +851,9 @@
         // streamType is the real stream type being affected, but for the UI sliders, we
         // refer to AudioService.STREAM_REMOTE_MUSIC. We still play the beeps on the real
         // stream type.
-        if (LOGD) Log.d(TAG, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
+        if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
 
-        if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || mDialog.isShowing()) {
+        if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || isShowing()) {
             synchronized (this) {
                 if (mActiveStreamType != AudioService.STREAM_REMOTE_MUSIC) {
                     reorderSliders(AudioService.STREAM_REMOTE_MUSIC);
@@ -805,7 +861,7 @@
                 onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, flags);
             }
         } else {
-            if (LOGD) Log.d(TAG, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
+            if (LOGD) Log.d(mTag, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
         }
 
         if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
@@ -825,8 +881,8 @@
     }
 
     protected void onRemoteVolumeUpdateIfShown() {
-        if (LOGD) Log.d(TAG, "onRemoteVolumeUpdateIfShown()");
-        if (mDialog.isShowing()
+        if (LOGD) Log.d(mTag, "onRemoteVolumeUpdateIfShown()");
+        if (isShowing()
                 && (mActiveStreamType == AudioService.STREAM_REMOTE_MUSIC)
                 && (mStreamControls != null)) {
             onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, 0);
@@ -842,7 +898,7 @@
      * @param visible
      */
     synchronized protected void onSliderVisibilityChanged(int streamType, int visible) {
-        if (LOGD) Log.d(TAG, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
+        if (LOGD) Log.d(mTag, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
         boolean isVisible = (visible == 1);
         for (int i = STREAMS.length - 1 ; i >= 0 ; i--) {
             StreamResources streamRes = STREAMS[i];
@@ -857,7 +913,7 @@
     }
 
     protected void onDisplaySafeVolumeWarning(int flags) {
-        if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || mDialog.isShowing()) {
+        if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || isShowing()) {
             synchronized (sConfirmSafeVolumeLock) {
                 if (sConfirmSafeVolumeDialog != null) {
                     return;
@@ -907,7 +963,7 @@
                     mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
                 } catch (RuntimeException e) {
                     if (LOGD) {
-                        Log.d(TAG, "ToneGenerator constructor failed with "
+                        Log.d(mTag, "ToneGenerator constructor failed with "
                                 + "RuntimeException: " + e);
                     }
                 }
@@ -976,8 +1032,10 @@
             }
 
             case MSG_TIMEOUT: {
-                if (mDialog.isShowing()) {
-                    mDialog.dismiss();
+                if (isShowing()) {
+                    if (mDialog != null) {
+                        mDialog.dismiss();
+                    }
                     mActiveStreamType = -1;
                 }
                 synchronized (sConfirmSafeVolumeLock) {
@@ -988,7 +1046,7 @@
                 break;
             }
             case MSG_RINGER_MODE_CHANGED: {
-                if (mDialog.isShowing()) {
+                if (isShowing()) {
                     updateStates();
                 }
                 break;
@@ -1010,17 +1068,30 @@
             case MSG_DISPLAY_SAFE_VOLUME_WARNING:
                 onDisplaySafeVolumeWarning(msg.arg1);
                 break;
+
+            case MSG_LAYOUT_DIRECTION:
+                setLayoutDirection(msg.arg1);
+                break;
+
+            case MSG_ZEN_MODE_CHANGED:
+                updateZenMode(msg.arg1 != 0);
+                break;
         }
     }
 
-    private void resetTimeout() {
+    public void resetTimeout() {
+        if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis());
         removeMessages(MSG_TIMEOUT);
-        sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY);
+        sendEmptyMessageDelayed(MSG_TIMEOUT, TIMEOUT_DELAY);
     }
 
     private void forceTimeout() {
         removeMessages(MSG_TIMEOUT);
-        sendMessage(obtainMessage(MSG_TIMEOUT));
+        sendEmptyMessage(MSG_TIMEOUT);
+    }
+
+    public ZenModeController getZenController() {
+        return mZenController;
     }
 
     private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
@@ -1061,10 +1132,22 @@
     private final View.OnClickListener mClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            if (v == mMoreButton) {
-                expand();
+            if (v == mExpandButton && mZenController != null) {
+                final boolean newZen = !mZenController.isZen();
+                mZenController.setZen(newZen);
+                if (newZen) {
+                    expand();
+                } else {
+                    collapse();
+                }
             }
             resetTimeout();
         }
     };
+
+    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+        public void onZenChanged(boolean zen) {
+            updateZenMode(zen);
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 9bd75b7..7da90d8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -1,16 +1,22 @@
 package com.android.systemui.volume;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.media.IVolumeController;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 
+import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 
 /*
  * Copyright (C) 2014 The Android Open Source Project
@@ -34,21 +40,21 @@
     private static final Uri SETTING_URI = Settings.Global.getUriFor(SETTING);
     private static final int DEFAULT = 1;  // enabled by default
 
+    private final Handler mHandler = new Handler();
     private AudioManager mAudioManager;
     private VolumeController mVolumeController;
 
     @Override
     public void start() {
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mVolumeController = new VolumeController(mContext);
+        putComponent(VolumeComponent.class, mVolumeController);
         updateController();
         mContext.getContentResolver().registerContentObserver(SETTING_URI, false, mObserver);
     }
 
     private void updateController() {
         if (Settings.Global.getInt(mContext.getContentResolver(), SETTING, DEFAULT) != 0) {
-            if (mVolumeController == null) {
-                mVolumeController = new VolumeController(mContext);
-            }
             Log.d(TAG, "Registering volume controller");
             mAudioManager.setVolumeController(mVolumeController);
         } else {
@@ -57,7 +63,7 @@
         }
     }
 
-    private final ContentObserver mObserver = new ContentObserver(new Handler()) {
+    private final ContentObserver mObserver = new ContentObserver(mHandler) {
         public void onChange(boolean selfChange, Uri uri) {
             if (SETTING_URI.equals(uri)) {
                 updateController();
@@ -66,13 +72,38 @@
     };
 
     /** For now, simply host an unmodified base volume panel in this process. */
-    private final class VolumeController extends IVolumeController.Stub {
-        private final VolumePanel mPanel;
+    private final class VolumeController extends IVolumeController.Stub implements VolumeComponent {
+        private final VolumePanel mDialogPanel;
+        private VolumePanel mPanel;
 
         public VolumeController(Context context) {
-            mPanel = new VolumePanel(context);
+            mPanel = new VolumePanel(context, null, new ZenModeControllerImpl(mContext, mHandler));
+            final int delay = context.getResources().getInteger(R.integer.feedback_start_delay);
+            mPanel.setZenModePanelCallback(new ZenModePanel.Callback() {
+                @Override
+                public void onMoreSettings() {
+                    mHandler.removeCallbacks(mStartZenSettings);
+                    mHandler.postDelayed(mStartZenSettings, delay);
+                }
+
+                @Override
+                public void onInteraction() {
+                    mDialogPanel.resetTimeout();
+                }
+            });
+            mDialogPanel = mPanel;
         }
 
+        private final Runnable mStartZenSettings = new Runnable() {
+            @Override
+            public void run() {
+                mDialogPanel.postDismiss();
+                final Intent intent = ZenModePanel.ZEN_SETTINGS;
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+            }
+        };
+
         @Override
         public void hasNewRemotePlaybackInfo() throws RemoteException {
             mPanel.postHasNewRemotePlaybackInfo();
@@ -114,12 +145,22 @@
         @Override
         public void setLayoutDirection(int layoutDirection)
                 throws RemoteException {
-            mPanel.setLayoutDirection(layoutDirection);
+            mPanel.postLayoutDirection(layoutDirection);
         }
 
         @Override
         public void dismiss() throws RemoteException {
             mPanel.postDismiss();
         }
+
+        @Override
+        public ZenModeController getZenController() {
+            return mDialogPanel.getZenController();
+        }
+
+        @Override
+        public void setVolumePanel(VolumePanel panel) {
+            mPanel = panel == null ? mDialogPanel : panel;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
new file mode 100644
index 0000000..77d267e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -0,0 +1,248 @@
+/*
+ * 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.volume;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+public class ZenModePanel extends LinearLayout {
+    private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+    public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+    private final LayoutInflater mInflater;
+    private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
+    private final H mHandler = new H();
+    private LinearLayout mConditions;
+    private int mMinutesIndex = Arrays.binarySearch(MINUTES, 60);  // default to one hour
+    private Callback mCallback;
+    private ZenModeController mController;
+    private boolean mRequestingConditions;
+
+    public ZenModePanel(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mConditions = (LinearLayout) findViewById(android.R.id.content);
+        findViewById(android.R.id.button2).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                fireMoreSettings();
+            }
+        });
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+        setRequestingConditions(visibility == VISIBLE);
+    }
+
+    /** Start or stop requesting relevant zen mode exit conditions */
+    private void setRequestingConditions(boolean requesting) {
+        if (mRequestingConditions == requesting) return;
+        mRequestingConditions = requesting;
+        if (mRequestingConditions) {
+            mController.addCallback(mZenCallback);
+        } else {
+            mController.removeCallback(mZenCallback);
+        }
+        mController.requestConditions(mRequestingConditions);
+    }
+
+    public void init(ZenModeController controller) {
+        mController = controller;
+        mConditions.removeAllViews();
+        bind(updateTimeCondition(), mConditions.getChildAt(0));
+        handleUpdateConditions(new Condition[0]);
+    }
+
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    private Condition updateTimeCondition() {
+        final int minutes = MINUTES[mMinutesIndex];
+        final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
+        final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
+                .appendPath("countdown").appendPath(Long.toString(millis)).build();
+        final int num = minutes < 60 ? minutes : minutes / 60;
+        final int resId = minutes < 60
+                ? R.plurals.zen_mode_duration_minutes
+                : R.plurals.zen_mode_duration_hours;
+        final String caption = mContext.getResources().getQuantityString(resId, num, num);
+        return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
+                Condition.FLAG_RELEVANT_NOW);
+    }
+
+    private void handleUpdateConditions(Condition[] conditions) {
+        final int newCount = conditions == null ? 0 : conditions.length;
+        for (int i = mConditions.getChildCount() - 1; i > newCount; i--) {
+            mConditions.removeViewAt(i);
+        }
+        for (int i = 0; i < newCount; i++) {
+            bind(conditions[i], mConditions.getChildAt(i + 1));
+        }
+        bind(null, mConditions.getChildAt(newCount + 1));
+    }
+
+    private void editTimeCondition(int delta) {
+        final int i = mMinutesIndex + delta;
+        if (i < 0 || i >= MINUTES.length) return;
+        mMinutesIndex = i;
+        final Condition c = updateTimeCondition();
+        bind(c, mConditions.getChildAt(0));
+    }
+
+    private void bind(final Condition condition, View convertView) {
+        final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE;
+        final View row;
+        if (convertView == null) {
+            row = mInflater.inflate(R.layout.zen_mode_condition, this, false);
+            mConditions.addView(row);
+        } else {
+            row = convertView;
+        }
+        final int position = mConditions.indexOfChild(row);
+        final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
+        mRadioButtons.add(rb);
+        rb.setEnabled(enabled);
+        rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    for (RadioButton otherButton : mRadioButtons) {
+                        if (otherButton == rb) continue;
+                        otherButton.setChecked(false);
+                    }
+                    mController.select(condition);
+                    fireInteraction();
+                }
+            }
+        });
+        final TextView title = (TextView) row.findViewById(android.R.id.title);
+        if (condition == null) {
+            title.setText(R.string.zen_mode_forever);
+        } else {
+            title.setText(condition.summary);
+        }
+        title.setEnabled(enabled);
+        title.setAlpha(enabled ? 1 : .5f);
+        final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
+        button1.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rb.setChecked(true);
+                editTimeCondition(-1);
+                fireInteraction();
+            }
+        });
+
+        final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
+        button2.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rb.setChecked(true);
+                editTimeCondition(1);
+                fireInteraction();
+            }
+        });
+        title.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rb.setChecked(true);
+                fireInteraction();
+            }
+        });
+        if (position == 0) {
+            button1.setEnabled(mMinutesIndex > 0);
+            button2.setEnabled(mMinutesIndex < MINUTES.length - 1);
+            button1.setImageAlpha(button1.isEnabled() ? 0xff : 0x7f);
+            button2.setImageAlpha(button2.isEnabled() ? 0xff : 0x7f);
+        } else {
+            button1.setVisibility(View.GONE);
+            button2.setVisibility(View.GONE);
+        }
+        if (position == 0 &&  mConditions.getChildCount() == 1) {
+            rb.setChecked(true);
+        }
+    }
+
+    private void fireMoreSettings() {
+        if (mCallback != null) {
+            mCallback.onMoreSettings();
+        }
+    }
+
+    private void fireInteraction() {
+        if (mCallback != null) {
+            mCallback.onInteraction();
+        }
+    }
+
+    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+        @Override
+        public void onConditionsChanged(Condition[] conditions) {
+            mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
+        }
+    };
+
+    private final class H extends Handler {
+        private static final int UPDATE_CONDITIONS = 1;
+
+        private H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == UPDATE_CONDITIONS) {
+                handleUpdateConditions((Condition[])msg.obj);
+            }
+        }
+    }
+
+    public interface Callback {
+        void onMoreSettings();
+        void onInteraction();
+    }
+}
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
index 79f8a1f..3c4e951 100644
--- a/packages/services/PacProcessor/Android.mk
+++ b/packages/services/PacProcessor/Android.mk
@@ -27,8 +27,6 @@
 
 LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor
 
-LOCAL_MULTILIB := 32
-
 include $(BUILD_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/services/PacProcessor/jni/Android.mk b/packages/services/PacProcessor/jni/Android.mk
index 8a60927..f16c90b 100644
--- a/packages/services/PacProcessor/jni/Android.mk
+++ b/packages/services/PacProcessor/jni/Android.mk
@@ -35,7 +35,6 @@
 
 LOCAL_MODULE := libjni_pacprocessor
 LOCAL_MODULE_TAGS := optional
-LOCAL_32_BIT_ONLY := true
 
 include external/stlport/libstlport.mk
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index d909568..3c37902 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -479,6 +479,7 @@
     private static final int MSG_DISABLE_POINTER_LOCATION = 2;
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
     private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
+    private static final int MSG_DISPATCH_SHOW_RECENTS = 5;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -496,6 +497,9 @@
                 case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK:
                     dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
                     break;
+                case MSG_DISPATCH_SHOW_RECENTS:
+                    showRecentApps(false);
+                    break;
             }
         }
     }
@@ -2455,6 +2459,12 @@
         }
     }
 
+    @Override
+    public void showRecentApps() {
+        mHandler.removeMessages(MSG_DISPATCH_SHOW_RECENTS);
+        mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_RECENTS);
+    }
+
     private void showRecentApps(boolean triggeredFromAltTab) {
         mPreloadedRecentApps = false; // preloading no longer needs to be canceled
         try {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 033b967..af0d443 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -988,7 +988,8 @@
                         sInfo.applicationInfo.packageName, sInfo.name);
                 if (userId > 0) {
                     if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
-                            sInfo.name, sInfo.flags)) {
+                            sInfo.name, sInfo.flags)
+                            && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                         userId = 0;
                         smap = getServiceMap(0);
                     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 248b44d..4b0187f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -283,7 +284,7 @@
     // before we decide it's never going to come up for real, when the process was
     // started with a wrapper for instrumentation (such as Valgrind) because it
     // could take much longer than usual.
-    static final int PROC_START_TIMEOUT_WITH_WRAPPER = 300*1000;
+    static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
 
     // How long to wait after going idle before forcing apps to GC.
     static final int GC_TIMEOUT = 5*1000;
@@ -409,7 +410,7 @@
     /**
      * List of intents that were used to start the most recent tasks.
      */
-    final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
+    ArrayList<TaskRecord> mRecentTasks;
 
     public class PendingAssistExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
@@ -822,6 +823,11 @@
     final AppOpsService mAppOpsService;
 
     /**
+     * Save recent tasks information across reboots.
+     */
+    final TaskPersister mTaskPersister;
+
+    /**
      * Current configuration information.  HistoryRecord objects are given
      * a reference to this object to indicate which configuration they are
      * currently running in, so this object must be kept immutable.
@@ -2138,6 +2144,7 @@
         mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
         mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
         mStackSupervisor = new ActivityStackSupervisor(this);
+        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);
 
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
@@ -2183,7 +2190,7 @@
         mBatteryStatsService.publish(mContext);
         mUsageStatsService.publish(mContext);
         mAppOpsService.publish(mContext);
-
+        Slog.d("AppOps", "AppOpsService published");
         LocalServices.addService(ActivityManagerInternal.class, new LocalService());
     }
 
@@ -7082,14 +7089,18 @@
      * Creates a new RecentTaskInfo from a TaskRecord.
      */
     private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
+        // Update the task description to reflect any changes in the task stack
+        tr.updateTaskDescription();
+
+        // Compose the recent task info
         ActivityManager.RecentTaskInfo rti
                 = new ActivityManager.RecentTaskInfo();
-        rti.id = tr.numActivities > 0 ? tr.taskId : -1;
+        rti.id = tr.mActivities.isEmpty() ? -1 : tr.taskId;
         rti.persistentId = tr.taskId;
         rti.baseIntent = new Intent(tr.getBaseIntent());
         rti.origActivity = tr.origActivity;
         rti.description = tr.lastDescription;
-        rti.stackId = tr.stack.mStackId;
+        rti.stackId = tr.stack != null ? tr.stack.mStackId : -1;
         rti.userId = tr.userId;
         rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
         return rti;
@@ -7323,6 +7334,9 @@
         if (tr != null) {
             tr.removeTaskActivitiesLocked(-1, false);
             cleanUpRemovedTaskLocked(tr, flags);
+            if (tr.isPersistable) {
+                notifyTaskPersisterLocked(tr, true);
+            }
             return true;
         }
         return false;
@@ -7562,14 +7576,11 @@
         try {
             synchronized (this) {
                 TaskRecord tr = recentTaskForIdLocked(taskId);
-                if (tr != null) {
-                    return tr.stack.isHomeStack();
-                }
+                return tr != null && tr.stack != null && tr.stack.isHomeStack();
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-        return false;
     }
 
     @Override
@@ -7727,7 +7738,7 @@
      * in {@link ContentProvider}.
      */
     private final String checkContentProviderPermissionLocked(
-            ProviderInfo cpi, ProcessRecord r, int userId) {
+            ProviderInfo cpi, ProcessRecord r, int userId, boolean checkUser) {
         final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
         final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
         final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
@@ -7744,8 +7755,10 @@
                 }
             }
         }
-        userId = handleIncomingUser(callingPid, callingUid, userId,
-                false, true, "checkContentProviderPermissionLocked", null);
+        if (checkUser) {
+            userId = handleIncomingUser(callingPid, callingUid, userId,
+                    false, true, "checkContentProviderPermissionLocked " + cpi.authority, null);
+        }
         if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
                 cpi.applicationInfo.uid, cpi.exported)
                 == PackageManager.PERMISSION_GRANTED) {
@@ -7880,13 +7893,34 @@
                 }
             }
 
+            boolean checkCrossUser = true;
+
             // First check if this content provider has been published...
             cpr = mProviderMap.getProviderByName(name, userId);
+            // If that didn't work, check if it exists for user 0 and then
+            // verify that it's a singleton provider before using it.
+            if (cpr == null && userId != UserHandle.USER_OWNER) {
+                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
+                if (cpr != null) {
+                    cpi = cpr.info;
+                    if (isSingleton(cpi.processName, cpi.applicationInfo,
+                            cpi.name, cpi.flags)
+                            && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
+                        userId = UserHandle.USER_OWNER;
+                        checkCrossUser = false;
+                    } else {
+                        cpr = null;
+                        cpi = null;
+                    }
+                }
+            }
+
             boolean providerRunning = cpr != null;
             if (providerRunning) {
                 cpi = cpr.info;
                 String msg;
-                if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) {
+                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
+                        != null) {
                     throw new SecurityException(msg);
                 }
 
@@ -7966,15 +8000,21 @@
                 if (cpi == null) {
                     return null;
                 }
+                // If the provider is a singleton AND
+                // (it's a call within the same user || the provider is a
+                // privileged app)
+                // Then allow connecting to the singleton provider
                 singleton = isSingleton(cpi.processName, cpi.applicationInfo,
-                        cpi.name, cpi.flags); 
+                        cpi.name, cpi.flags)
+                        && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
                 if (singleton) {
-                    userId = 0;
+                    userId = UserHandle.USER_OWNER;
                 }
                 cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
 
                 String msg;
-                if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) {
+                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
+                        != null) {
                     throw new SecurityException(msg);
                 }
 
@@ -8638,6 +8678,10 @@
         }
     }
 
+    void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
+        mTaskPersister.notify(task, flush);
+    }
+
     @Override
     public boolean shutdown(int timeout) {
         if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
@@ -8660,6 +8704,7 @@
         synchronized (this) {
             mProcessStats.shutdownLocked();
         }
+        notifyTaskPersisterLocked(null, true);
 
         return timedout;
     }
@@ -9565,7 +9610,15 @@
                 if (goingCallback != null) goingCallback.run();
                 return;
             }
-            
+
+            if (mRecentTasks == null) {
+                mRecentTasks = mTaskPersister.restoreTasksLocked();
+                if (!mRecentTasks.isEmpty()) {
+                    mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks);
+                }
+                mTaskPersister.startPersisting();
+            }
+
             // Check to see if there are any update receivers to run.
             if (!mDidUpdate) {
                 if (mWaitingUpdate) {
@@ -10540,8 +10593,7 @@
         // assume our apps are happy - lazy create the list
         List<ActivityManager.ProcessErrorStateInfo> errList = null;
 
-        final boolean allUsers = ActivityManager.checkUidPermission(
-                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+        final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
                 Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED;
         int userId = UserHandle.getUserId(Binder.getCallingUid());
 
@@ -10630,8 +10682,7 @@
         enforceNotIsolatedCaller("getRunningAppProcesses");
         // Lazy instantiation of list
         List<ActivityManager.RunningAppProcessInfo> runList = null;
-        final boolean allUsers = ActivityManager.checkUidPermission(
-                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+        final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
                 Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED;
         int userId = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (this) {
@@ -13071,8 +13122,7 @@
                 if ((requireFull || checkComponentPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS,
                         callingPid, callingUid, -1, true) != PackageManager.PERMISSION_GRANTED)
-                        && checkComponentPermission(
-                                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                        && checkComponentPermission(INTERACT_ACROSS_USERS_FULL,
                                 callingPid, callingUid, -1, true)
                                 != PackageManager.PERMISSION_GRANTED) {
                     if (userId == UserHandle.USER_CURRENT_OR_SELF) {
@@ -13092,7 +13142,7 @@
                         builder.append(" but is calling from user ");
                         builder.append(UserHandle.getUserId(callingUid));
                         builder.append("; this requires ");
-                        builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+                        builder.append(INTERACT_ACROSS_USERS_FULL);
                         if (!requireFull) {
                             builder.append(" or ");
                             builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
@@ -13122,8 +13172,9 @@
     boolean isSingleton(String componentProcessName, ApplicationInfo aInfo,
             String className, int flags) {
         boolean result = false;
+        // For apps that don't have pre-defined UIDs, check for permission
         if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
-            if ((flags&ServiceInfo.FLAG_SINGLE_USER) != 0) {
+            if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
                 if (ActivityManager.checkUidPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS,
                         aInfo.uid) != PackageManager.PERMISSION_GRANTED) {
@@ -13134,12 +13185,14 @@
                     Slog.w(TAG, msg);
                     throw new SecurityException(msg);
                 }
+                // Permission passed
                 result = true;
             }
-        } else if (componentProcessName == aInfo.packageName) {
-            result = (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
         } else if ("system".equals(componentProcessName)) {
             result = true;
+        } else {
+            // App with pre-defined UID, check if it's a persistent app
+            result = (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
         }
         if (DEBUG_MU) {
             Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo
@@ -13148,6 +13201,21 @@
         return result;
     }
 
+    /**
+     * Checks to see if the caller is in the same app as the singleton
+     * component, or the component is in a special app. It allows special apps
+     * to export singleton components but prevents exporting singleton
+     * components for regular apps.
+     */
+    boolean isValidSingletonCall(int callingUid, int componentUid) {
+        int componentAppId = UserHandle.getAppId(componentUid);
+        return UserHandle.isSameApp(callingUid, componentUid)
+                || componentAppId == Process.SYSTEM_UID
+                || componentAppId == Process.PHONE_UID
+                || ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, componentUid)
+                        == PackageManager.PERMISSION_GRANTED;
+    }
+
     public int bindService(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType,
             IServiceConnection connection, int flags, int userId) {
@@ -13694,8 +13762,8 @@
          */
         int callingAppId = UserHandle.getAppId(callingUid);
         if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
-            || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID ||
-            callingUid == 0) {
+                || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
+                || callingUid == 0) {
             // Always okay.
         } else if (callerApp == null || !callerApp.persistent) {
             try {
@@ -16505,12 +16573,12 @@
     }
 
     private boolean startUser(final int userId, boolean foreground) {
-        if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+        if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: switchUser() from pid="
                     + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
-                    + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+                    + " requires " + INTERACT_ACROSS_USERS_FULL;
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
@@ -16876,12 +16944,12 @@
 
     @Override
     public int stopUser(final int userId, final IStopUserCallback callback) {
-        if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+        if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: switchUser() from pid="
                     + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
-                    + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+                    + " requires " + INTERACT_ACROSS_USERS_FULL;
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
@@ -17019,7 +17087,7 @@
     public UserInfo getCurrentUser() {
         if ((checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
                 != PackageManager.PERMISSION_GRANTED) && (
-                checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                 != PackageManager.PERMISSION_GRANTED)) {
             String msg = "Permission Denial: getCurrentUser() from pid="
                     + Binder.getCallingPid()
@@ -17105,12 +17173,12 @@
 
     @Override
     public void registerUserSwitchObserver(IUserSwitchObserver observer) {
-        if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+        if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: registerUserSwitchObserver() from pid="
                     + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
-                    + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+                    + " requires " + INTERACT_ACROSS_USERS_FULL;
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
@@ -17182,7 +17250,7 @@
 
     /**
      * An implementation of IAppTask, that allows an app to manage its own tasks via
-     * {@link android.app.ActivityManager#AppTask}.  We keep track of the callingUid to ensure that
+     * {@link android.app.ActivityManager.AppTask}.  We keep track of the callingUid to ensure that
      * only the process that calls getAppTasks() can call the AppTask methods.
      */
     class AppTaskImpl extends IAppTask.Stub {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index dbe2ca1..b429b93 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,14 +16,15 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager.TaskDescription;
 import android.os.PersistableBundle;
 import android.os.Trace;
 import com.android.internal.app.ResolverActivity;
+import com.android.internal.util.XmlUtils;
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 
-import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ResultInfo;
 import android.content.ComponentName;
@@ -48,7 +49,11 @@
 import android.util.TimeUtils;
 import android.view.IApplicationToken;
 import android.view.WindowManager;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -62,6 +67,19 @@
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
     final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
 
+    private static final String TAG_ACTIVITY = "activity";
+    private static final String ATTR_ID = "id";
+    private static final String TAG_INTENT = "intent";
+    private static final String ATTR_USERID = "user_id";
+    private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
+    private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
+    private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
+    private static final String ATTR_RESOLVEDTYPE = "resolved_type";
+    private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
+    private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label";
+    private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color";
+    private static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
+
     final ActivityManagerService service; // owner
     final IApplicationToken.Stub appToken; // window manager token
     final ActivityInfo info; // all about me
@@ -97,6 +115,7 @@
     int windowFlags;        // custom window flags for preview window.
     TaskRecord task;        // the task this is in.
     ThumbnailHolder thumbHolder; // where our thumbnails should go.
+    long createTime = System.currentTimeMillis();
     long displayStartTime;  // when we started launching this activity
     long fullyDrawnStartTime; // when we started launching this activity
     long startTime;         // last time this activity was started
@@ -149,7 +168,7 @@
     boolean mStartingWindowShown = false;
     ActivityContainer mInitialActivityContainer;
 
-    ActivityManager.TaskDescription taskDescription; // the recents information for this activity
+    TaskDescription taskDescription; // the recents information for this activity
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
@@ -490,14 +509,6 @@
                         (newTask == null ? null : newTask.stack));
             }
         }
-        if (inHistory && !finishing) {
-            if (task != null) {
-                task.numActivities--;
-            }
-            if (newTask != null) {
-                newTask.numActivities++;
-            }
-        }
         if (newThumbHolder == null) {
             newThumbHolder = newTask;
         }
@@ -527,9 +538,6 @@
     void putInHistory() {
         if (!inHistory) {
             inHistory = true;
-            if (task != null && !finishing) {
-                task.numActivities++;
-            }
         }
     }
 
@@ -537,7 +545,6 @@
         if (inHistory) {
             inHistory = false;
             if (task != null && !finishing) {
-                task.numActivities--;
                 task = null;
             }
             clearOptionsLocked();
@@ -560,12 +567,13 @@
         return mActivityType == APPLICATION_ACTIVITY_TYPE;
     }
 
+    boolean isPersistable() {
+        return (info.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
+    }
+
     void makeFinishing() {
         if (!finishing) {
             finishing = true;
-            if (task != null && inHistory) {
-                task.numActivities--;
-            }
             if (stopped) {
                 clearOptionsLocked();
             }
@@ -767,6 +775,9 @@
                         "Setting thumbnail of " + this + " holder " + thumbHolder
                         + " to " + newThumbnail);
                 thumbHolder.lastThumbnail = newThumbnail;
+                if (isPersistable()) {
+                    mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
+                }
             }
             thumbHolder.lastDescription = description;
         }
@@ -1042,7 +1053,134 @@
         return null;
     }
 
-    private String activityTypeToString(int type) {
+    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+        out.attribute(null, ATTR_ID, String.valueOf(createTime));
+        out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
+        if (launchedFromPackage != null) {
+            out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
+        }
+        if (resolvedType != null) {
+            out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
+        }
+        out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
+        out.attribute(null, ATTR_USERID, String.valueOf(userId));
+        if (taskDescription != null) {
+            final String label = taskDescription.getLabel();
+            if (label != null) {
+                out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
+            }
+            final int colorPrimary = taskDescription.getPrimaryColor();
+            if (colorPrimary != 0) {
+                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
+            }
+            final Bitmap icon = taskDescription.getIcon();
+            if (icon != null) {
+                TaskPersister.saveImage(icon, String.valueOf(task.taskId) + ACTIVITY_ICON_SUFFIX +
+                        createTime);
+            }
+        }
+
+        out.startTag(null, TAG_INTENT);
+        intent.saveToXml(out);
+        out.endTag(null, TAG_INTENT);
+
+        if (isPersistable() && persistentState != null) {
+            out.startTag(null, TAG_PERSISTABLEBUNDLE);
+            persistentState.saveToXml(out);
+            out.endTag(null, TAG_PERSISTABLEBUNDLE);
+        }
+    }
+
+    static ActivityRecord restoreFromXml(XmlPullParser in, int taskId,
+            ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException {
+        Intent intent = null;
+        PersistableBundle persistentState = null;
+        int launchedFromUid = 0;
+        String launchedFromPackage = null;
+        String resolvedType = null;
+        boolean componentSpecified = false;
+        int userId = 0;
+        String activityLabel = null;
+        int activityColor = 0;
+        long createTime = -1;
+        final int outerDepth = in.getDepth();
+
+        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
+            final String attrName = in.getAttributeName(attrNdx);
+            final String attrValue = in.getAttributeValue(attrNdx);
+            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: attribute name=" +
+                    attrName + " value=" + attrValue);
+            if (ATTR_ID.equals(attrName)) {
+                createTime = Long.valueOf(attrValue);
+            } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) {
+                launchedFromUid = Integer.valueOf(attrValue);
+            } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
+                launchedFromPackage = attrValue;
+            } else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
+                resolvedType = attrValue;
+            } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
+                componentSpecified = Boolean.valueOf(attrValue);
+            } else if (ATTR_USERID.equals(attrName)) {
+                userId = Integer.valueOf(attrValue);
+            } else if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
+                activityLabel = attrValue;
+            } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
+                activityColor = (int) Long.parseLong(attrValue, 16);
+            } else {
+                Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
+            }
+        }
+
+        int event;
+        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
+                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
+            if (event == XmlPullParser.START_TAG) {
+                final String name = in.getName();
+                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
+                        "ActivityRecord: START_TAG name=" + name);
+                if (TAG_INTENT.equals(name)) {
+                    intent = Intent.restoreFromXml(in);
+                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
+                            "ActivityRecord: intent=" + intent);
+                } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
+                    persistentState = PersistableBundle.restoreFromXml(in);
+                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
+                            "ActivityRecord: persistentState=" + persistentState);
+                } else {
+                    Slog.w(TAG, "restoreActivity: unexpected name=" + name);
+                    XmlUtils.skipCurrentTag(in);
+                }
+            }
+        }
+
+        if (intent == null) {
+            throw new XmlPullParserException("restoreActivity error intent=" + intent);
+        }
+
+        final ActivityManagerService service = stackSupervisor.mService;
+        final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
+                null, userId);
+        if (aInfo == null) {
+            throw new XmlPullParserException("restoreActivity resolver error.");
+        }
+        final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
+                launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
+                null, null, 0, componentSpecified, stackSupervisor, null, null);
+
+        r.persistentState = persistentState;
+
+        Bitmap icon = null;
+        if (createTime >= 0) {
+            icon = TaskPersister.restoreImage(String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX +
+                    createTime);
+        }
+        r.taskDescription = new TaskDescription(activityLabel, icon, activityColor);
+        r.createTime = createTime;
+
+        return r;
+    }
+
+    private static String activityTypeToString(int type) {
         switch (type) {
             case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
             case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index df80f02..a0440cb 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -30,6 +30,10 @@
 import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY;
 import static com.android.server.am.ActivityManagerService.VALIDATE_TOKENS;
 
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
@@ -880,7 +884,10 @@
         final ActivityRecord r = isInStackLocked(token);
         if (r != null) {
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-            r.persistentState = persistentState;
+            if (persistentState != null) {
+                r.persistentState = persistentState;
+                mService.notifyTaskPersisterLocked(r.task, false);
+            }
             if (mPausingActivity == r) {
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
                         + (timeout ? " (due to timeout)" : " (pause complete)"));
@@ -902,7 +909,10 @@
             mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
             return;
         }
-        r.persistentState = persistentState;
+        if (persistentState != null) {
+            r.persistentState = persistentState;
+            mService.notifyTaskPersisterLocked(r.task, false);
+        }
         if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
         if (icicle != null) {
             // If icicle is null, this is happening due to a timeout, so we
@@ -1057,40 +1067,6 @@
         }
     }
 
-    /**
-     * Determine if home should be visible below the passed record.
-     * @param record activity we are querying for.
-     * @return true if home is visible below the passed activity, false otherwise.
-     */
-    boolean isActivityOverHome(ActivityRecord record) {
-        // Start at record and go down, look for either home or a visible fullscreen activity.
-        final TaskRecord recordTask = record.task;
-        for (int taskNdx = mTaskHistory.indexOf(recordTask); taskNdx >= 0; --taskNdx) {
-            TaskRecord task = mTaskHistory.get(taskNdx);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
-            final int startNdx =
-                    task == recordTask ? activities.indexOf(record) : activities.size() - 1;
-            for (int activityNdx = startNdx; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.isHomeActivity()) {
-                    return true;
-                }
-                if (!r.finishing && r.fullscreen) {
-                    // Passed activity is over a fullscreen activity.
-                    return false;
-                }
-            }
-            if (task.mOnTopOfHome) {
-                // Got to the bottom of a task on top of home without finding a visible fullscreen
-                // activity. Home is visible.
-                return true;
-            }
-        }
-        // Got to the bottom of this stack and still don't know. If this is over the home stack
-        // then record is over home. May not work if we ever get more than two layers.
-        return mStackSupervisor.isFrontStack(this);
-    }
-
     private void setVisibile(ActivityRecord r, boolean visible) {
         r.visible = visible;
         mWindowManager.setAppVisibility(r.appToken, visible);
@@ -1120,7 +1096,8 @@
         for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
             final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
             for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
-                final ArrayList<ActivityRecord> activities = tasks.get(taskNdx).mActivities;
+                final TaskRecord task = tasks.get(taskNdx);
+                final ArrayList<ActivityRecord> activities = task.mActivities;
                 for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
                     final ActivityRecord r = activities.get(activityNdx);
 
@@ -1131,7 +1108,7 @@
                     // - Full Screen Activity OR
                     // - On top of Home and our stack is NOT home
                     if (!r.finishing && r.visible && (r.fullscreen ||
-                            (!isHomeStack() && r.frontOfTask && tasks.get(taskNdx).mOnTopOfHome))) {
+                            (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()))) {
                         return false;
                     }
                 }
@@ -1259,7 +1236,7 @@
                         // At this point, nothing else needs to be shown
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
                         behindFullscreen = true;
-                    } else if (!isHomeStack() && r.frontOfTask && task.mOnTopOfHome) {
+                    } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
                         behindFullscreen = true;
                     }
@@ -1413,6 +1390,7 @@
         final boolean userLeaving = mStackSupervisor.mUserLeaving;
         mStackSupervisor.mUserLeaving = false;
 
+        final TaskRecord prevTask = prev != null ? prev.task : null;
         if (next == null) {
             // There are no more activities!  Let's just start up the
             // Launcher...
@@ -1420,7 +1398,10 @@
             if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             // Only resume home if on home display
-            return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev);
+            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
+                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
+            return isOnHomeDisplay() &&
+                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
         }
 
         next.delayedResume = false;
@@ -1439,22 +1420,24 @@
         }
 
         final TaskRecord nextTask = next.task;
-        final TaskRecord prevTask = prev != null ? prev.task : null;
         if (prevTask != null && prevTask.stack == this &&
-                prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
+                prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
             if (prevTask == nextTask) {
                 prevTask.setFrontOfTask();
             } else if (prevTask != topTask()) {
-                // This task is going away but it was supposed to return to the home task.
+                // This task is going away but it was supposed to return to the home stack.
                 // Now the task above it has to return to the home task instead.
                 final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
-                mTaskHistory.get(taskNdx).mOnTopOfHome = true;
+                mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);
             } else {
                 if (DEBUG_STATES && isOnHomeDisplay()) Slog.d(TAG,
                         "resumeTopActivityLocked: Launching home next");
                 // Only resume home if on home display
-                return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev);
+                final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
+                        HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
+                return isOnHomeDisplay() &&
+                        mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
             }
         }
 
@@ -1825,10 +1808,11 @@
             ActivityStack lastStack = mStackSupervisor.getLastStack();
             final boolean fromHome = lastStack.isHomeStack();
             if (!isHomeStack() && (fromHome || topTask() != task)) {
-                task.mOnTopOfHome = fromHome;
+                task.setTaskToReturnTo(fromHome ?
+                        lastStack.topTask().taskType : APPLICATION_ACTIVITY_TYPE);
             }
         } else {
-            task.mOnTopOfHome = false;
+            task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
         }
 
         mTaskHistory.remove(task);
@@ -1844,6 +1828,7 @@
             ++stackNdx;
         }
         mTaskHistory.add(stackNdx, task);
+        updateTaskMovement(task, true);
     }
 
     final void startActivityLocked(ActivityRecord r, boolean newTask,
@@ -2372,8 +2357,8 @@
             ActivityRecord next = topRunningActivityLocked(null);
             if (next != r) {
                 final TaskRecord task = r.task;
-                if (r.frontOfTask && task == topTask() && task.mOnTopOfHome) {
-                    mStackSupervisor.moveHomeToTop();
+                if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
+                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo());
                 }
             }
             ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
@@ -2857,8 +2842,9 @@
         if (task != null && task.removeActivity(r)) {
             if (DEBUG_STACK) Slog.i(TAG,
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
-            if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) {
-                mStackSupervisor.moveHomeToTop();
+            if (mStackSupervisor.isFrontStack(this) && task == topTask() &&
+                    task.isOverHomeStack()) {
+                mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo());
             }
             removeTask(task);
         }
@@ -3161,14 +3147,28 @@
         mWindowManager.prepareAppTransition(transit, false);
     }
 
-    void moveHomeTaskToTop() {
+    void updateTaskMovement(TaskRecord task, boolean toFront) {
+        if (task.isPersistable) {
+            task.mLastTimeMoved = System.currentTimeMillis();
+            // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
+            // recently will be most negative, tasks sent to the bottom before that will be less
+            // negative. Similarly for recent tasks moved to the top which will be most positive.
+            if (!toFront) {
+                task.mLastTimeMoved *= -1;
+            }
+        }
+    }
+
+    void moveHomeStackTaskToTop(int homeStackTaskType) {
         final int top = mTaskHistory.size() - 1;
         for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
-            if (task.isHomeTask()) {
-                if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG, "moveHomeTaskToTop: moving " + task);
+            if (task.taskType == homeStackTaskType) {
+                if (DEBUG_TASKS || DEBUG_STACK)
+                    Slog.d(TAG, "moveHomeStackTaskToTop: moving " + task);
                 mTaskHistory.remove(taskNdx);
                 mTaskHistory.add(top, task);
+                updateTaskMovement(task, true);
                 mWindowManager.moveTaskToTop(task.taskId);
                 return;
             }
@@ -3270,19 +3270,19 @@
 
         mTaskHistory.remove(tr);
         mTaskHistory.add(0, tr);
+        updateTaskMovement(tr, false);
 
         // There is an assumption that moving a task to the back moves it behind the home activity.
         // We make sure here that some activity in the stack will launch home.
-        ActivityRecord lastActivity = null;
         int numTasks = mTaskHistory.size();
         for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
-            if (task.mOnTopOfHome) {
+            if (task.isOverHomeStack()) {
                 break;
             }
             if (taskNdx == 1) {
                 // Set the last task before tr to go to home.
-                task.mOnTopOfHome = true;
+                task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
             }
         }
 
@@ -3303,9 +3303,10 @@
         }
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
-        if (task == tr && tr.mOnTopOfHome || numTasks <= 1 && isOnHomeDisplay()) {
-            tr.mOnTopOfHome = false;
-            return mStackSupervisor.resumeHomeActivity(null);
+        if (task == tr && tr.isOverHomeStack() || numTasks <= 1 && isOnHomeDisplay()) {
+            final int taskToReturnTo = tr.getTaskToReturnTo();
+            tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null);
         }
 
         mStackSupervisor.resumeTopActivitiesLocked();
@@ -3746,10 +3747,14 @@
 
         final int taskNdx = mTaskHistory.indexOf(task);
         final int topTaskNdx = mTaskHistory.size() - 1;
-        if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
-            mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
+        if (task.isOverHomeStack() && taskNdx < topTaskNdx) {
+            final TaskRecord nextTask = mTaskHistory.get(taskNdx + 1);
+            if (!nextTask.isOverHomeStack()) {
+                nextTask.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+            }
         }
         mTaskHistory.remove(task);
+        updateTaskMovement(task, true);
 
         if (task.mActivities.isEmpty()) {
             final boolean isVoiceSession = task.voiceSession != null;
@@ -3781,7 +3786,8 @@
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             boolean toTop) {
-        TaskRecord task = new TaskRecord(taskId, info, intent, voiceSession, voiceInteractor);
+        TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
+                voiceInteractor);
         addTask(task, toTop, false);
         return task;
     }
@@ -3796,6 +3802,7 @@
             insertTaskAtTop(task);
         } else {
             mTaskHistory.add(0, task);
+            updateTaskMovement(task, false);
         }
         if (!moving && task.voiceSession != null) {
             try {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index adc7aff..92f41f7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -31,6 +31,9 @@
 import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
 import static com.android.server.am.ActivityManagerService.TAG;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -45,6 +48,7 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.IActivityManager.WaitResult;
 import android.app.ResultInfo;
+import android.app.StatusBarManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentSender;
@@ -73,6 +77,7 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
@@ -88,11 +93,13 @@
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.TransferPipe;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.wm.WindowManagerService;
 
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -128,9 +135,15 @@
     static final int HANDLE_DISPLAY_CHANGED = FIRST_SUPERVISOR_STACK_MSG + 6;
     static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7;
     static final int CONTAINER_CALLBACK_VISIBILITY = FIRST_SUPERVISOR_STACK_MSG + 8;
+    static final int LOCK_TASK_START_MSG = FIRST_SUPERVISOR_STACK_MSG + 9;
+    static final int LOCK_TASK_END_MSG = FIRST_SUPERVISOR_STACK_MSG + 10;
 
     private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
 
+    /** Status Bar Service **/
+    private IBinder mToken = new Binder();
+    private IStatusBarService mStatusBarService;
+
     // For debugging to make sure the caller when acquiring/releasing our
     // wake lock is the system process.
     static final boolean VALIDATE_WAKE_LOCK_CALLER = false;
@@ -249,6 +262,21 @@
         mLaunchingActivity.setReferenceCounted(false);
     }
 
+    // This function returns a IStatusBarService. The value is from ServiceManager.
+    // getService and is cached.
+    private IStatusBarService getStatusBarService() {
+        synchronized (mService) {
+            if (mStatusBarService == null) {
+                mStatusBarService = IStatusBarService.Stub.asInterface(
+                    ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
+                if (mStatusBarService == null) {
+                    Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
+                }
+            }
+            return mStatusBarService;
+        }
+    }
+
     void setWindowManager(WindowManagerService wm) {
         synchronized (mService) {
             mWindowManager = wm;
@@ -319,18 +347,27 @@
         }
     }
 
-    void moveHomeToTop() {
+    void moveHomeStackTaskToTop(int homeStackTaskType) {
+        if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
+            mWindowManager.showRecentApps();
+            return;
+        }
         moveHomeStack(true);
-        mHomeStack.moveHomeTaskToTop();
+        mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
     }
 
-    boolean resumeHomeActivity(ActivityRecord prev) {
-        moveHomeToTop();
-        if (prev != null) {
-            prev.task.mOnTopOfHome = false;
+    boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev) {
+        if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
+            mWindowManager.showRecentApps();
+            return false;
         }
+        moveHomeStackTaskToTop(homeStackTaskType);
+        if (prev != null) {
+            prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+        }
+
         ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
-        if (r != null && r.isHomeActivity()) {
+        if (r != null && (r.isHomeActivity() || r.isRecentsActivity())) {
             mService.setFocusedActivityLocked(r);
             return resumeTopActivitiesLocked(mHomeStack, prev, null);
         }
@@ -371,6 +408,12 @@
         return null;
     }
 
+    void setNextTaskId(int taskId) {
+        if (taskId > mCurTaskId) {
+            mCurTaskId = taskId;
+        }
+    }
+
     int getNextTaskId() {
         do {
             mCurTaskId++;
@@ -678,7 +721,7 @@
     }
 
     void startHomeActivity(Intent intent, ActivityInfo aInfo) {
-        moveHomeToTop();
+        moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE);
         startActivityLocked(null, intent, null, aInfo, null, null, null, null, 0, 0, 0, null, 0,
                 null, false, null, null);
     }
@@ -1195,8 +1238,7 @@
             requestCode = sourceRecord.requestCode;
             sourceRecord.resultTo = null;
             if (resultRecord != null) {
-                resultRecord.removeResultsLocked(
-                    sourceRecord, resultWho, requestCode);
+                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
             }
             if (sourceRecord.launchedFromUid == callingUid) {
                 // The new activity is being launched from the same uid as the previous
@@ -1368,7 +1410,7 @@
         return err;
     }
 
-    ActivityStack adjustStackFocus(ActivityRecord r) {
+    ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
         final TaskRecord task = r.task;
         if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) {
             if (task != null) {
@@ -1393,7 +1435,8 @@
                 return container.mStack;
             }
 
-            if (mFocusedStack != mHomeStack) {
+            if (mFocusedStack != mHomeStack && (!newTask ||
+                    mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                         "adjustStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
@@ -1446,7 +1489,7 @@
 
         // We'll invoke onUserLeaving before onPause only if the launching
         // activity did not explicitly state that this is an automated launch.
-        mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+        mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
         if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
 
         // If the caller has asked not to resume at this point, we make note
@@ -1456,7 +1499,8 @@
             r.delayedResume = true;
         }
 
-        ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+        ActivityRecord notTop =
+                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
 
         // If the onlyIfNeeded flag is set, then we can do this if the activity
         // being launched is the same as the one making the call...  or, as
@@ -1479,9 +1523,11 @@
             case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
                 intent.addFlags(
                         Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                launchFlags = intent.getFlags();
                 break;
             case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+                launchFlags = intent.getFlags();
                 break;
         }
         final boolean newDocument = intent.isDocument();
@@ -1610,7 +1656,7 @@
                                     (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                     == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                 // Caller wants to appear on home activity.
-                                intentActivity.task.mOnTopOfHome = true;
+                                intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                             }
                             options = null;
                         }
@@ -1787,26 +1833,31 @@
                 Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
-            targetStack = adjustStackFocus(r);
+            newTask = true;
+            targetStack = adjustStackFocus(r, newTask);
             targetStack.moveToFront();
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                         newTaskInfo != null ? newTaskInfo : r.info,
                         newTaskIntent != null ? newTaskIntent : intent,
                         voiceSession, voiceInteractor, true), null, true);
+                if (sourceRecord == null) {
+                    // Launched from a service or notification or task that is finishing.
+                    r.task.setTaskToReturnTo(isFrontStack(mHomeStack) ?
+                            mHomeStack.topTask().taskType : RECENTS_ACTIVITY_TYPE);
+                }
                 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                         r.task);
             } else {
                 r.setTask(reuseTask, reuseTask, true);
             }
-            newTask = true;
             if (!movedHome) {
                 if ((launchFlags &
                         (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
                         == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
                     // Caller wants to appear on home activity, so before starting
                     // their own activity we will bring home to the front.
-                    r.task.mOnTopOfHome = r.task.stack.isOnHomeDisplay();
+                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                 }
             }
         } else if (sourceRecord != null) {
@@ -1867,7 +1918,7 @@
             // This not being started from an existing activity, and not part
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
-            targetStack = adjustStackFocus(r);
+            targetStack = adjustStackFocus(r, newTask);
             targetStack.moveToFront();
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task
@@ -2157,7 +2208,7 @@
         if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
             // Caller wants the home activity moved with it.  To accomplish this,
             // we'll just indicate that this task returns to the home task.
-            task.mOnTopOfHome = true;
+            task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
         }
         task.stack.moveTaskToFrontLocked(task, null, options);
         if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
@@ -2251,6 +2302,26 @@
         return mLastStackId;
     }
 
+    void createStackForRestoredTaskHistory(ArrayList<TaskRecord> tasks) {
+        int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
+        final ActivityStack stack = getStack(stackId);
+        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = tasks.get(taskNdx);
+            stack.addTask(task, false, false);
+            final int taskId = task.taskId;
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                mWindowManager.addAppToken(0, r.appToken, taskId, stackId,
+                        r.info.screenOrientation, r.fullscreen,
+                        (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
+                        r.userId, r.info.configChanges);
+            }
+            mWindowManager.addTask(taskId, stackId, false);
+        }
+        resumeHomeStackTask(HOME_ACTIVITY_TYPE, null);
+    }
+
     void moveTaskToStack(int taskId, int stackId, boolean toTop) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
@@ -2274,7 +2345,12 @@
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 if (!r.isApplicationActivity() && !stack.isHomeStack()) {
-                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack);
+                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
+                    continue;
+                }
+                if (!stack.mActivityContainer.isEligibleForNewTasks()) {
+                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
+                            stack);
                     continue;
                 }
                 final ActivityRecord ar = stack.findTaskLocked(r);
@@ -2505,7 +2581,7 @@
             }
         } else {
             // Stack was moved to another display while user was swapped out.
-            resumeHomeActivity(null);
+            resumeHomeStackTask(HOME_ACTIVITY_TYPE, null);
         }
         return homeInFront;
     }
@@ -2898,9 +2974,12 @@
     }
 
     void setLockTaskModeLocked(TaskRecord task) {
+        final Message lockTaskMsg = Message.obtain();
         if (task == null) {
             // Take out of lock task mode.
             mLockTaskModeTask = null;
+            lockTaskMsg.what = LOCK_TASK_END_MSG;
+            mHandler.sendMessage(lockTaskMsg);
             return;
         }
         if (isLockTaskModeViolation(task)) {
@@ -2910,6 +2989,8 @@
         mLockTaskModeTask = task;
         findTaskToMoveToFrontLocked(task, 0, null);
         resumeTopActivitiesLocked();
+        lockTaskMsg.what = LOCK_TASK_START_MSG;
+        mHandler.sendMessage(lockTaskMsg);
     }
 
     boolean isLockTaskModeViolation(TaskRecord task) {
@@ -3006,6 +3087,32 @@
                     } catch (RemoteException e) {
                     }
                 }
+                case LOCK_TASK_START_MSG: {
+                    // When lock task starts, we disable the status bars.
+                    try {
+                        if (getStatusBarService() != null) {
+                            getStatusBarService().disable
+                                (StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK,
+                                mToken, mService.mContext.getPackageName());
+                        }
+                    } catch (RemoteException ex) {
+                        throw new RuntimeException(ex);
+                    }
+                    break;
+                }
+                case LOCK_TASK_END_MSG: {
+                    // When lock task ends, we enable the status bars.
+                    try {
+                       if (getStatusBarService() != null) {
+                           getStatusBarService().disable
+                               (StatusBarManager.DISABLE_NONE,
+                               mToken, mService.mContext.getPackageName());
+                       }
+                    } catch (RemoteException ex) {
+                        throw new RuntimeException(ex);
+                    }
+                    break;
+                }
             }
         }
     }
@@ -3205,6 +3312,11 @@
         void setDrawn() {
         }
 
+        // You can always start a new task on a regular ActivityStack.
+        boolean isEligibleForNewTasks() {
+            return true;
+        }
+
         @Override
         public String toString() {
             return mIdString + (mActivityDisplay == null ? "N" : "A");
@@ -3285,6 +3397,12 @@
             }
         }
 
+        // Never start a new task on an ActivityView if it isn't explicitly specified.
+        @Override
+        boolean isEligibleForNewTasks() {
+            return false;
+        }
+
         private void setSurfaceIfReady() {
             if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 9d6481a..7b2b04d 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -27,6 +27,7 @@
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
@@ -858,7 +859,10 @@
             r.state = BroadcastRecord.APP_RECEIVE;
             String targetProcess = info.activityInfo.processName;
             r.curComponent = component;
-            if (r.callingUid != Process.SYSTEM_UID && isSingleton) {
+            final int receiverUid = info.activityInfo.applicationInfo.uid;
+            // If it's a singleton, it needs to be the same app or a special app
+            if (r.callingUid != Process.SYSTEM_UID && isSingleton
+                    && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
                 info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
             }
             r.curReceiver = info.activityInfo;
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
new file mode 100644
index 0000000..3bfaca9
--- /dev/null
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Debug;
+import android.os.SystemClock;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class TaskPersister {
+    static final String TAG = "TaskPersister";
+    static final boolean DEBUG = false;
+
+    /** When in slow mode don't write tasks out faster than this */
+    private static final long INTER_TASK_DELAY_MS = 60000;
+    private static final long DEBUG_INTER_TASK_DELAY_MS = 5000;
+
+    private static final String RECENTS_FILENAME = "_task";
+    private static final String TASKS_DIRNAME = "recent_tasks";
+    private static final String TASK_EXTENSION = ".xml";
+    private static final String IMAGES_DIRNAME = "recent_images";
+    private static final String IMAGE_EXTENSION = ".png";
+
+    private static final String TAG_TASK = "task";
+
+    private static File sImagesDir;
+    private static File sTasksDir;
+
+    private final ActivityManagerService mService;
+    private final ActivityStackSupervisor mStackSupervisor;
+
+    private boolean mRecentsChanged = false;
+
+    private final LazyTaskWriterThread mLazyTaskWriterThread;
+
+    TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor) {
+        sTasksDir = new File(systemDir, TASKS_DIRNAME);
+        if (!sTasksDir.exists()) {
+            if (!sTasksDir.mkdir()) {
+                Slog.e(TAG, "Failure creating tasks directory " + sTasksDir);
+            }
+        }
+
+        sImagesDir = new File(systemDir, IMAGES_DIRNAME);
+        if (!sImagesDir.exists()) {
+            if (!sImagesDir.mkdir()) {
+                Slog.e(TAG, "Failure creating images directory " + sImagesDir);
+            }
+        }
+
+        mStackSupervisor = stackSupervisor;
+        mService = stackSupervisor.mService;
+
+        mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThread");
+    }
+
+    void startPersisting() {
+        mLazyTaskWriterThread.start();
+    }
+
+    public void notify(TaskRecord task, boolean flush) {
+        if (DEBUG) Slog.d(TAG, "notify: task=" + task + " flush=" + flush +
+                " Callers=" + Debug.getCallers(4));
+        if (task != null) {
+            task.needsPersisting = true;
+        }
+        synchronized (this) {
+            mLazyTaskWriterThread.mSlow = !flush;
+            mRecentsChanged = true;
+            notifyAll();
+        }
+    }
+
+    private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException {
+        if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
+        final XmlSerializer xmlSerializer = new FastXmlSerializer();
+        StringWriter stringWriter = new StringWriter();
+        xmlSerializer.setOutput(stringWriter);
+
+        if (DEBUG) xmlSerializer.setFeature(
+                    "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+        // save task
+        xmlSerializer.startDocument(null, true);
+
+        xmlSerializer.startTag(null, TAG_TASK);
+        task.saveToXml(xmlSerializer);
+        xmlSerializer.endTag(null, TAG_TASK);
+
+        xmlSerializer.endDocument();
+        xmlSerializer.flush();
+
+        return stringWriter;
+    }
+
+    static void saveImage(Bitmap image, String filename) throws IOException {
+        if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename);
+        FileOutputStream imageFile = null;
+        try {
+            imageFile = new FileOutputStream(new File(sImagesDir, filename + IMAGE_EXTENSION));
+            image.compress(Bitmap.CompressFormat.PNG, 100, imageFile);
+        } catch (Exception e) {
+            Slog.e(TAG, "saveImage: unable to save " + filename, e);
+        } finally {
+            if (imageFile != null) {
+                imageFile.close();
+            }
+        }
+    }
+
+    ArrayList<TaskRecord> restoreTasksLocked() {
+        final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
+        ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
+
+        File[] recentFiles = sTasksDir.listFiles();
+        if (recentFiles == null) {
+            Slog.e(TAG, "Unable to list files from " + sTasksDir);
+            return tasks;
+        }
+
+        for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
+            File taskFile = recentFiles[taskNdx];
+            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
+            BufferedReader reader = null;
+            boolean deleteFile = false;
+            try {
+                reader = new BufferedReader(new FileReader(taskFile));
+                final XmlPullParser in = Xml.newPullParser();
+                in.setInput(reader);
+
+                int event;
+                while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
+                        event != XmlPullParser.END_TAG) {
+                    final String name = in.getName();
+                    if (event == XmlPullParser.START_TAG) {
+                        if (DEBUG) Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
+                        if (TAG_TASK.equals(name)) {
+                            final TaskRecord task =
+                                    TaskRecord.restoreFromXml(in, mStackSupervisor);
+                            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" + task);
+                            if (task != null) {
+                                tasks.add(task);
+                                final int taskId = task.taskId;
+                                recoveredTaskIds.add(taskId);
+                                mStackSupervisor.setNextTaskId(taskId);
+                            }
+                        } else {
+                            Slog.e(TAG, "restoreTasksLocked Unknown xml event=" + event + " name="
+                                    + name);
+                        }
+                    }
+                    XmlUtils.skipCurrentTag(in);
+                }
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Unable to parse " + taskFile + ". Error " + e);
+                deleteFile = true;
+            } finally {
+                if (reader != null) {
+                    try {
+                        reader.close();
+                    } catch (IOException e) {
+                    }
+                }
+                if (!DEBUG && deleteFile) {
+                    taskFile.delete();
+                }
+            }
+        }
+
+        if (!DEBUG) {
+            removeObsoleteFiles(recoveredTaskIds);
+        }
+
+        TaskRecord[] tasksArray = new TaskRecord[tasks.size()];
+        tasks.toArray(tasksArray);
+        Arrays.sort(tasksArray, new Comparator<TaskRecord>() {
+            @Override
+            public int compare(TaskRecord lhs, TaskRecord rhs) {
+                final long diff = lhs.mLastTimeMoved - rhs.mLastTimeMoved;
+                if (diff < 0) {
+                    return -1;
+                } else if (diff > 0) {
+                    return +1;
+                } else {
+                    return 0;
+                }
+            }
+        });
+
+        return new ArrayList<TaskRecord>(Arrays.asList(tasksArray));
+    }
+
+    private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
+        for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
+            File file = files[fileNdx];
+            String filename = file.getName();
+            final int taskIdEnd = filename.indexOf('_') + 1;
+            if (taskIdEnd > 0) {
+                final int taskId;
+                try {
+                    taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
+                } catch (Exception e) {
+                    if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Can't parse file=" +
+                            file.getName());
+                    file.delete();
+                    continue;
+                }
+                if (!persistentTaskIds.contains(taskId)) {
+                    if (DEBUG) Slog.d(TAG, "removeObsoleteFile: deleting file=" + file.getName());
+                    file.delete();
+                }
+            }
+        }
+    }
+
+    private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) {
+        removeObsoleteFiles(persistentTaskIds, sTasksDir.listFiles());
+        removeObsoleteFiles(persistentTaskIds, sImagesDir.listFiles());
+    }
+
+    static Bitmap restoreImage(String filename) {
+        if (DEBUG) Slog.d(TAG, "restoreImage: restoring " + filename);
+        return BitmapFactory.decodeFile(sImagesDir + File.separator + filename + IMAGE_EXTENSION);
+    }
+
+    private class LazyTaskWriterThread extends Thread {
+        boolean mSlow = true;
+
+        LazyTaskWriterThread(String name) {
+            super(name);
+        }
+
+        @Override
+        public void run() {
+            ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>();
+            while (true) {
+                // If mSlow, then delay between each call to saveToXml().
+                synchronized (TaskPersister.this) {
+                    long now = SystemClock.uptimeMillis();
+                    final long releaseTime =
+                            now + (DEBUG ? DEBUG_INTER_TASK_DELAY_MS: INTER_TASK_DELAY_MS);
+                    while (mSlow && now < releaseTime) {
+                        try {
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting " +
+                                    (releaseTime - now));
+                            TaskPersister.this.wait(releaseTime - now);
+                        } catch (InterruptedException e) {
+                        }
+                        now = SystemClock.uptimeMillis();
+                    }
+                }
+
+                StringWriter stringWriter = null;
+                TaskRecord task = null;
+                synchronized(mService) {
+                    final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
+                    persistentTaskIds.clear();
+                    for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                        task = tasks.get(taskNdx);
+                        if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
+                                task.isPersistable + " needsPersisting=" + task.needsPersisting);
+                        if (task.isPersistable) {
+                            persistentTaskIds.add(task.taskId);
+
+                            if (task.needsPersisting) {
+                                try {
+                                    stringWriter = saveToXml(task);
+                                    break;
+                                } catch (IOException e) {
+                                } catch (XmlPullParserException e) {
+                                } finally {
+                                    task.needsPersisting = false;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (stringWriter != null) {
+                    // Write out xml file while not holding mService lock.
+                    FileOutputStream file = null;
+                    AtomicFile atomicFile = null;
+                    try {
+                        atomicFile = new AtomicFile(new File(sTasksDir,
+                                String.valueOf(task.taskId) + RECENTS_FILENAME + TASK_EXTENSION));
+                        file = atomicFile.startWrite();
+                        file.write(stringWriter.toString().getBytes());
+                        file.write('\n');
+                        atomicFile.finishWrite(file);
+                    } catch (IOException e) {
+                        if (file != null) {
+                            atomicFile.failWrite(file);
+                        }
+                        Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " + e);
+                    }
+                } else {
+                    // Made it through the entire list and didn't find anything new that needed
+                    // persisting.
+                    if (!DEBUG) {
+                        removeObsoleteFiles(persistentTaskIds);
+                    }
+
+                    // Wait here for someone to call setRecentsChanged().
+                    synchronized (TaskPersister.this) {
+                        while (!mRecentsChanged) {
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: Waiting.");
+                            try {
+                                TaskPersister.this.wait();
+                            } catch (InterruptedException e) {
+                            }
+                        }
+                        mRecentsChanged = false;
+                        if (DEBUG) Slog.d(TAG, "LazyTaskWriter: Awake");
+                    }
+                }
+                // Some recents file needs to be written.
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 6d66b29..c07bc1e 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -17,6 +17,9 @@
 package com.android.server.am;
 
 import static com.android.server.am.ActivityManagerService.TAG;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
 
 import android.app.Activity;
@@ -27,15 +30,38 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.Slog;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
 final class TaskRecord extends ThumbnailHolder {
+    private static final String TAG_TASK = "task";
+    private static final String ATTR_TASKID = "task_id";
+    private static final String TAG_INTENT = "intent";
+    private static final String TAG_AFFINITYINTENT = "affinity_intent";
+    private static final String ATTR_REALACTIVITY = "real_activity";
+    private static final String ATTR_ORIGACTIVITY = "orig_activity";
+    private static final String TAG_ACTIVITY = "activity";
+    private static final String ATTR_AFFINITY = "affinity";
+    private static final String ATTR_ROOTHASRESET = "root_has_reset";
+    private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
+    private static final String ATTR_USERID = "user_id";
+    private static final String ATTR_TASKTYPE = "task_type";
+    private static final String ATTR_LASTDESCRIPTION = "last_description";
+    private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
+
+    private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
+
     final int taskId;       // Unique identifier for this task.
     final String affinity;  // The affinity name for this task, or null.
     final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
@@ -62,25 +88,64 @@
             new ActivityManager.TaskDescription();
 
     /** List of all activities in the task arranged in history order */
-    final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mActivities;
 
     /** Current stack */
     ActivityStack stack;
 
     /** Takes on same set of values as ActivityRecord.mActivityType */
-    private int mTaskType;
+    int taskType;
 
-    /** Launch the home activity when leaving this task. Will be false for tasks that are not on
-     * Display.DEFAULT_DISPLAY. */
-    boolean mOnTopOfHome = false;
+    /** Takes on same value as first root activity */
+    boolean isPersistable = false;
 
-    TaskRecord(int _taskId, ActivityInfo info, Intent _intent,
+    /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
+     * determining the order when restoring. Sign indicates whether last task movement was to front
+     * (positive) or back (negative). Absolute value indicates time. */
+    long mLastTimeMoved = System.currentTimeMillis();
+
+    /** True if persistable, has changed, and has not yet been persisted */
+    boolean needsPersisting = false;
+
+    /** Indication of what to run next when task exits. Use ActivityRecord types.
+     * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
+     * task stack. */
+    private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
+
+    final ActivityManagerService mService;
+
+    TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
+        mService = service;
         taskId = _taskId;
         affinity = info.taskAffinity;
         voiceSession = _voiceSession;
         voiceInteractor = _voiceInteractor;
         setIntent(_intent, info);
+        mActivities = new ArrayList<ActivityRecord>();
+    }
+
+    TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
+            String _affinity, ComponentName _realActivity, ComponentName _origActivity,
+            boolean _rootWasReset, boolean _askedCompatMode, int _taskType, int _userId,
+            String _lastDescription, ArrayList<ActivityRecord> activities, long lastTimeMoved) {
+        mService = service;
+        taskId = _taskId;
+        intent = _intent;
+        affinityIntent = _affinityIntent;
+        affinity = _affinity;
+        voiceSession = null;
+        voiceInteractor = null;
+        realActivity = _realActivity;
+        origActivity = _origActivity;
+        rootWasReset = _rootWasReset;
+        askedCompatMode = _askedCompatMode;
+        taskType = _taskType;
+        mTaskToReturnTo = HOME_ACTIVITY_TYPE;
+        userId = _userId;
+        lastDescription = _lastDescription;
+        mActivities = activities;
+        mLastTimeMoved = lastTimeMoved;
     }
 
     void touchActiveTime() {
@@ -144,6 +209,14 @@
         }
     }
 
+    void setTaskToReturnTo(int taskToReturnTo) {
+        mTaskToReturnTo = taskToReturnTo;
+    }
+
+    int getTaskToReturnTo() {
+        return mTaskToReturnTo;
+    }
+
     void disposeThumbnail() {
         super.disposeThumbnail();
         for (int i=mActivities.size()-1; i>=0; i--) {
@@ -237,12 +310,16 @@
         }
         // Only set this based on the first activity
         if (mActivities.isEmpty()) {
-            mTaskType = r.mActivityType;
+            taskType = r.mActivityType;
+            isPersistable = r.isPersistable();
         } else {
             // Otherwise make all added activities match this one.
-            r.mActivityType = mTaskType;
+            r.mActivityType = taskType;
         }
         mActivities.add(index, r);
+        if (r.isPersistable()) {
+            mService.notifyTaskPersisterLocked(this, false);
+        }
     }
 
     /** @return true if this was the last activity in the task */
@@ -251,6 +328,9 @@
             // Was previously in list.
             numFullscreen--;
         }
+        if (r.isPersistable()) {
+            mService.notifyTaskPersisterLocked(this, false);
+        }
         return mActivities.size() == 0;
     }
 
@@ -270,7 +350,14 @@
             if (r.finishing) {
                 continue;
             }
-            if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear", false)) {
+            if (stack == null) {
+                // Task was restored from persistent storage.
+                r.takeFromHistory();
+                mActivities.remove(activityNdx);
+                --activityNdx;
+                --numActivities;
+            } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
+                    false)) {
                 --activityNdx;
                 --numActivities;
             }
@@ -354,11 +441,13 @@
     }
 
     public Bitmap getTaskTopThumbnailLocked() {
-        final ActivityRecord resumedActivity = stack.mResumedActivity;
-        if (resumedActivity != null && resumedActivity.task == this) {
-            // This task is the current resumed task, we just need to take
-            // a screenshot of it and return that.
-            return stack.screenshotActivities(resumedActivity);
+        if (stack != null) {
+            final ActivityRecord resumedActivity = stack.mResumedActivity;
+            if (resumedActivity != null && resumedActivity.task == this) {
+                // This task is the current resumed task, we just need to take
+                // a screenshot of it and return that.
+                return stack.screenshotActivities(resumedActivity);
+            }
         }
         // Return the information about the task, to figure out the top
         // thumbnail to return.
@@ -399,11 +488,15 @@
     }
 
     boolean isHomeTask() {
-        return mTaskType == ActivityRecord.HOME_ACTIVITY_TYPE;
+        return taskType == HOME_ACTIVITY_TYPE;
     }
 
     boolean isApplicationTask() {
-        return mTaskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+        return taskType == APPLICATION_ACTIVITY_TYPE;
+    }
+
+    boolean isOverHomeStack() {
+        return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
     }
 
     public TaskAccessInfo getTaskAccessInfoLocked() {
@@ -493,7 +586,7 @@
         int activityNdx;
         final int numActivities = mActivities.size();
         for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
-             ++activityNdx) {
+                ++activityNdx) {
             final ActivityRecord r = mActivities.get(activityNdx);
             if (r.intent != null &&
                     (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
@@ -528,14 +621,152 @@
         }
     }
 
+    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+        Slog.i(TAG, "Saving task=" + this);
+
+        out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
+        if (realActivity != null) {
+            out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
+        }
+        if (origActivity != null) {
+            out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
+        }
+        if (affinity != null) {
+            out.attribute(null, ATTR_AFFINITY, affinity);
+        }
+        out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
+        out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
+        out.attribute(null, ATTR_USERID, String.valueOf(userId));
+        out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
+        out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
+        if (lastDescription != null) {
+            out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
+        }
+
+        if (affinityIntent != null) {
+            out.startTag(null, TAG_AFFINITYINTENT);
+            affinityIntent.saveToXml(out);
+            out.endTag(null, TAG_AFFINITYINTENT);
+        }
+
+        out.startTag(null, TAG_INTENT);
+        intent.saveToXml(out);
+        out.endTag(null, TAG_INTENT);
+
+        final ArrayList<ActivityRecord> activities = mActivities;
+        final int numActivities = activities.size();
+        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+            final ActivityRecord r = activities.get(activityNdx);
+            if (!r.isPersistable() || (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
+                    Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) {
+                break;
+            }
+            out.startTag(null, TAG_ACTIVITY);
+            r.saveToXml(out);
+            out.endTag(null, TAG_ACTIVITY);
+        }
+
+        final Bitmap thumbnail = getTaskTopThumbnailLocked();
+        if (thumbnail != null) {
+            TaskPersister.saveImage(thumbnail, String.valueOf(taskId) + TASK_THUMBNAIL_SUFFIX);
+        }
+    }
+
+    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+            throws IOException, XmlPullParserException {
+        Intent intent = null;
+        Intent affinityIntent = null;
+        ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
+        ComponentName realActivity = null;
+        ComponentName origActivity = null;
+        String affinity = null;
+        boolean rootHasReset = false;
+        boolean askedCompatMode = false;
+        int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+        int userId = 0;
+        String lastDescription = null;
+        long lastTimeOnTop = 0;
+        int taskId = -1;
+        final int outerDepth = in.getDepth();
+
+        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
+            final String attrName = in.getAttributeName(attrNdx);
+            final String attrValue = in.getAttributeValue(attrNdx);
+            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
+                    attrName + " value=" + attrValue);
+            if (ATTR_TASKID.equals(attrName)) {
+                taskId = Integer.valueOf(attrValue);
+            } else if (ATTR_REALACTIVITY.equals(attrName)) {
+                realActivity = ComponentName.unflattenFromString(attrValue);
+            } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
+                origActivity = ComponentName.unflattenFromString(attrValue);
+            } else if (ATTR_AFFINITY.equals(attrName)) {
+                affinity = attrValue;
+            } else if (ATTR_ROOTHASRESET.equals(attrName)) {
+                rootHasReset = Boolean.valueOf(attrValue);
+            } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
+                askedCompatMode = Boolean.valueOf(attrValue);
+            } else if (ATTR_USERID.equals(attrName)) {
+                userId = Integer.valueOf(attrValue);
+            } else if (ATTR_TASKTYPE.equals(attrName)) {
+                taskType = Integer.valueOf(attrValue);
+            } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
+                lastDescription = attrValue;
+            } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
+                lastTimeOnTop = Long.valueOf(attrValue);
+            } else {
+                Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
+            }
+        }
+
+        int event;
+        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
+                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
+            if (event == XmlPullParser.START_TAG) {
+                final String name = in.getName();
+                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
+                        name);
+                if (TAG_AFFINITYINTENT.equals(name)) {
+                    affinityIntent = Intent.restoreFromXml(in);
+                } else if (TAG_INTENT.equals(name)) {
+                    intent = Intent.restoreFromXml(in);
+                } else if (TAG_ACTIVITY.equals(name)) {
+                    ActivityRecord activity =
+                            ActivityRecord.restoreFromXml(in, taskId, stackSupervisor);
+                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
+                            activity);
+                    if (activity != null) {
+                        activities.add(activity);
+                    }
+                } else {
+                    Slog.e(TAG, "restoreTask: Unexpected name=" + name);
+                    XmlUtils.skipCurrentTag(in);
+                }
+            }
+        }
+
+        final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
+                affinityIntent, affinity, realActivity, origActivity, rootHasReset,
+                askedCompatMode, taskType, userId, lastDescription, activities, lastTimeOnTop);
+
+        for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
+            final ActivityRecord r = activities.get(activityNdx);
+            r.thumbHolder = r.task = task;
+        }
+
+        task.lastThumbnail = TaskPersister.restoreImage(taskId + TASK_THUMBNAIL_SUFFIX);
+
+        Slog.i(TAG, "Restored task=" + task);
+        return task;
+    }
+
     void dump(PrintWriter pw, String prefix) {
-        if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
-            pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
-                    pw.print(" rootWasReset="); pw.print(rootWasReset);
+        if (rootWasReset || userId != 0 || numFullscreen != 0) {
+            pw.print(prefix); pw.print(" rootWasReset="); pw.print(rootWasReset);
                     pw.print(" userId="); pw.print(userId);
-                    pw.print(" mTaskType="); pw.print(mTaskType);
+                    pw.print(" taskType="); pw.print(taskType);
                     pw.print(" numFullscreen="); pw.print(numFullscreen);
-                    pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
+                    pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
         }
         if (affinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.println(affinity);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 92b5f52..c93f85d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -489,8 +489,10 @@
     }
 
     private class StateReceiver extends BroadcastReceiver {
+        @Override
         public void onReceive(Context content, Intent intent) {
             String action = intent.getAction();
+            if (action == null) { return; }
             if (action.equals(UsbManager.ACTION_USB_STATE)) {
                 synchronized (Tethering.this.mPublicSync) {
                     boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index c7d2871..8fd55e7 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -230,7 +230,7 @@
         // Notify for any user other than the caller's own requires permission.
         final int callingUserHandle = UserHandle.getCallingUserId();
         if (userHandle != callingUserHandle) {
-            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
                     "no permission to notify other users");
         }
 
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
index f8e9b7b..0ba7773 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -133,7 +133,8 @@
 
         @Override
         public void sendTimerMessage(int state, long delayMillis) {
-            sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state), delayMillis);
+            // The third argument(0) is not used.
+            sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state, 0), delayMillis);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 662159d..3c18a59 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -20,8 +20,11 @@
 import android.hardware.hdmi.HdmiCecDeviceInfo;
 import android.hardware.hdmi.HdmiCecMessage;
 import android.os.Handler;
+import android.os.Looper;
+import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
+
+import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
 
 import libcore.util.EmptyArray;
 
@@ -34,6 +37,9 @@
  * and pass it to CEC HAL so that it sends message to other device. For incoming
  * message it translates the message and delegates it to proper module.
  *
+ * <p>It should be careful to access member variables on IO thread because
+ * it can be accessed from system thread as well.
+ *
  * <p>It can be created only by {@link HdmiCecController#create}
  *
  * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
@@ -55,8 +61,7 @@
 
     private static final int NUM_LOGICAL_ADDRESS = 16;
 
-    // TODO: define other constants for errors.
-    private static final int ERROR_SUCCESS = 0;
+    private static final int RETRY_COUNT_FOR_LOGICAL_ADDRESS_ALLOCATION = 3;
 
     // Handler instance to process synchronous I/O (mainly send) message.
     private Handler mIoHandler;
@@ -67,22 +72,19 @@
 
     // Stores the pointer to the native implementation of the service that
     // interacts with HAL.
-    private long mNativePtr;
+    private volatile long mNativePtr;
 
     private HdmiControlService mService;
 
-    // Map-like container of all cec devices. A logical address of device is
-    // used as key of container.
-    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos =
-            new SparseArray<HdmiCecDeviceInfo>();
-    // Set-like container for all local devices' logical address.
-    // Key and value are same.
-    private final SparseIntArray mLocalAddresses = new SparseIntArray();
+    // Map-like container of all cec devices including local ones.
+    // A logical address of device is used as key of container.
+    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>();
+
+    // Stores the local CEC devices in the system. Device type is used for key.
+    private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>();
 
     // Private constructor.  Use HdmiCecController.create().
     private HdmiCecController() {
-        // TODO: Consider restoring the local device addresses from persistent storage
-        //       to allocate the same addresses again if possible.
     }
 
     /**
@@ -96,53 +98,42 @@
      *         returns {@code null}.
      */
     static HdmiCecController create(HdmiControlService service) {
-        HdmiCecController handler = new HdmiCecController();
-        long nativePtr = nativeInit(handler);
+        HdmiCecController controller = new HdmiCecController();
+        long nativePtr = nativeInit(controller);
         if (nativePtr == 0L) {
-            handler = null;
+            controller = null;
             return null;
         }
 
-        handler.init(service, nativePtr);
-        return handler;
+        controller.init(service, nativePtr);
+        return controller;
+    }
+
+    private void init(HdmiControlService service, long nativePtr) {
+        mService = service;
+        mIoHandler = new Handler(service.getServiceLooper());
+        mControlHandler = new Handler(service.getServiceLooper());
+        mNativePtr = nativePtr;
     }
 
     /**
-     * Initialize {@link #mLocalAddresses} by allocating logical addresses for each hosted type.
+     * Perform initialization for each hosted device.
      *
-     * @param deviceTypes local device types
+     * @param deviceTypes array of device types
      */
     void initializeLocalDevices(int[] deviceTypes) {
-        for (int deviceType : deviceTypes) {
-            int preferred = getPreferredAddress(deviceType);
-            allocateLogicalAddress(deviceType, preferred, new AllocateLogicalAddressCallback() {
-                @Override
-                public void onAllocated(int deviceType, int logicalAddress) {
-                    addLogicalAddress(logicalAddress);
-                }
-            });
-        }
-    }
-
-    /**
-     * Get the preferred address for a given type.
-     *
-     * @param deviceType logical device type to get the address for
-     * @return preferred address; {@link HdmiCec#ADDR_UNREGISTERED} if not available.
-     */
-    private int getPreferredAddress(int deviceType) {
-        // Uses the data restored from persistent memory at boot up if they are available.
-        // Otherwise we return UNREGISTERED indicating there is no preferred address.
-        // Note that for address SPECIFIC_USE(14), HdmiCec.getTypeFromAddress() returns DEVICE_TV,
-        // meaning that we do not support device type video processor yet.
-        for (int i = 0; i < mLocalAddresses.size(); ++i) {
-            int address = mLocalAddresses.keyAt(i);
-            int type = HdmiCec.getTypeFromAddress(address);
-            if (type == deviceType) {
-                return address;
+        assertRunOnServiceThread();
+        for (int type : deviceTypes) {
+            HdmiCecLocalDevice device = HdmiCecLocalDevice.create(this, type);
+            if (device == null) {
+                continue;
             }
+            // TODO: Consider restoring the local device addresses from persistent storage
+            //       to allocate the same addresses again if possible.
+            device.setPreferredAddress(HdmiCec.ADDR_UNREGISTERED);
+            mLocalDevices.put(type, device);
+            device.init();
         }
-        return HdmiCec.ADDR_UNREGISTERED;
     }
 
     /**
@@ -175,6 +166,8 @@
      */
     void allocateLogicalAddress(final int deviceType, final int preferredAddress,
             final AllocateLogicalAddressCallback callback) {
+        assertRunOnServiceThread();
+
         runOnIoThread(new Runnable() {
             @Override
             public void run() {
@@ -185,6 +178,7 @@
 
     private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress,
             final AllocateLogicalAddressCallback callback) {
+        assertRunOnIoThread();
         int startAddress = preferredAddress;
         // If preferred address is "unregistered", start address will be the smallest
         // address matched with the given device type.
@@ -202,15 +196,8 @@
         for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
             int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
             if (curAddress != HdmiCec.ADDR_UNREGISTERED
-                    && deviceType == HdmiCec.getTypeFromAddress(i)) {
-                // <Polling Message> is a message which has empty body and
-                // uses same address for both source and destination address.
-                // If sending <Polling Message> failed (NAK), it becomes
-                // new logical address for the device because no device uses
-                // it as logical address of the device.
-                int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress,
-                        EMPTY_BODY);
-                if (error != ERROR_SUCCESS) {
+                    && deviceType == HdmiCec.getTypeFromAddress(curAddress)) {
+                if (!sendPollMessage(curAddress, RETRY_COUNT_FOR_LOGICAL_ADDRESS_ALLOCATION)) {
                     logicalAddress = curAddress;
                     break;
                 }
@@ -246,6 +233,7 @@
      *         that has the same logical address as new one has.
      */
     HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+        assertRunOnServiceThread();
         HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
         if (oldDeviceInfo != null) {
             removeDeviceInfo(deviceInfo.getLogicalAddress());
@@ -264,6 +252,7 @@
      * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
      */
     HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
+        assertRunOnServiceThread();
         HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
         if (deviceInfo != null) {
             mDeviceInfos.remove(logicalAddress);
@@ -272,13 +261,14 @@
     }
 
     /**
-     * Return a list of all {@HdmiCecDeviceInfo}.
+     * Return a list of all {@link HdmiCecDeviceInfo}.
      *
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      */
     List<HdmiCecDeviceInfo> getDeviceInfoList() {
-        List<HdmiCecDeviceInfo> deviceInfoList = new ArrayList<HdmiCecDeviceInfo>(
-                mDeviceInfos.size());
+        assertRunOnServiceThread();
+
+        List<HdmiCecDeviceInfo> deviceInfoList = new ArrayList<>(mDeviceInfos.size());
         for (int i = 0; i < mDeviceInfos.size(); ++i) {
             deviceInfoList.add(mDeviceInfos.valueAt(i));
         }
@@ -295,10 +285,22 @@
      *         Returns null if no logical address matched
      */
     HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+        assertRunOnServiceThread();
         return mDeviceInfos.get(logicalAddress);
     }
 
     /**
+     * Return the locally hosted logical device of a given type.
+     *
+     * @param deviceType logical device type
+     * @return {@link HdmiCecLocalDevice} instance if the instance of the type is available;
+     *          otherwise null.
+     */
+    HdmiCecLocalDevice getLocalDevice(int deviceType) {
+        return mLocalDevices.get(deviceType);
+    }
+
+    /**
      * Add a new logical address to the device. Device's HW should be notified
      * when a new logical address is assigned to a device, so that it can accept
      * a command having available destinations.
@@ -309,8 +311,8 @@
      * @return 0 on success. Otherwise, returns negative value
      */
     int addLogicalAddress(int newLogicalAddress) {
+        assertRunOnServiceThread();
         if (HdmiCec.isValidAddress(newLogicalAddress)) {
-            mLocalAddresses.put(newLogicalAddress, newLogicalAddress);
             return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
         } else {
             return -1;
@@ -323,9 +325,12 @@
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      */
     void clearLogicalAddress() {
+        assertRunOnServiceThread();
         // TODO: consider to backup logical address so that new logical address
         // allocation can use it as preferred address.
-        mLocalAddresses.clear();
+        for (int i = 0; i < mLocalDevices.size(); ++i) {
+            mLocalDevices.valueAt(i).clearAddress();
+        }
         nativeClearLogicalAddress(mNativePtr);
     }
 
@@ -338,6 +343,7 @@
      *         is between 0x0000 and 0xFFFF. If failed it returns -1
      */
     int getPhysicalAddress() {
+        assertRunOnServiceThread();
         return nativeGetPhysicalAddress(mNativePtr);
     }
 
@@ -347,6 +353,7 @@
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      */
     int getVersion() {
+        assertRunOnServiceThread();
         return nativeGetVersion(mNativePtr);
     }
 
@@ -356,9 +363,96 @@
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      */
     int getVendorId() {
+        assertRunOnServiceThread();
         return nativeGetVendorId(mNativePtr);
     }
 
+    /**
+     * Poll all remote devices. It sends &lt;Polling Message&gt; to all remote
+     * devices.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param callback an interface used to get a list of all remote devices' address
+     * @param retryCount the number of retry used to send polling message to remote devices
+     */
+    void pollDevices(DevicePollingCallback callback, int retryCount) {
+        assertRunOnServiceThread();
+        // Extract polling candidates. No need to poll against local devices.
+        ArrayList<Integer> pollingCandidates = new ArrayList<>();
+        for (int i = HdmiCec.ADDR_SPECIFIC_USE; i >= HdmiCec.ADDR_TV; --i) {
+            if (!isAllocatedLocalDeviceAddress(i)) {
+                pollingCandidates.add(i);
+            }
+        }
+
+        runDevicePolling(pollingCandidates, retryCount, callback);
+    }
+
+    private boolean isAllocatedLocalDeviceAddress(int address) {
+        for (int i = 0; i < mLocalDevices.size(); ++i) {
+            if (mLocalDevices.valueAt(i).isAddressOf(address)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void runDevicePolling(final List<Integer> candidates, final int retryCount,
+            final DevicePollingCallback callback) {
+        assertRunOnServiceThread();
+        runOnIoThread(new Runnable() {
+            @Override
+            public void run() {
+                final ArrayList<Integer> allocated = new ArrayList<>();
+                for (Integer address : candidates) {
+                    if (sendPollMessage(address, retryCount)) {
+                        allocated.add(address);
+                    }
+                }
+                if (callback != null) {
+                    runOnServiceThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            callback.onPollingFinished(allocated);
+                        }
+                    });
+                }
+            }
+        });
+    }
+
+    private boolean sendPollMessage(int address, int retryCount) {
+        assertRunOnIoThread();
+        for (int i = 0; i < retryCount; ++i) {
+            // <Polling Message> is a message which has empty body and
+            // uses same address for both source and destination address.
+            // If sending <Polling Message> failed (NAK), it becomes
+            // new logical address for the device because no device uses
+            // it as logical address of the device.
+            if (nativeSendCecCommand(mNativePtr, address, address, EMPTY_BODY)
+                    == HdmiControlService.SEND_RESULT_SUCCESS) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void assertRunOnIoThread() {
+        if (Looper.myLooper() != mIoHandler.getLooper()) {
+            throw new IllegalStateException("Should run on io thread.");
+        }
+    }
+
+    private void assertRunOnServiceThread() {
+        if (Looper.myLooper() != mControlHandler.getLooper()) {
+            throw new IllegalStateException("Should run on service thread.");
+        }
+    }
+
+    // Run a Runnable on IO thread.
+    // It should be careful to access member variables on IO thread because
+    // it can be accessed from system thread as well.
     private void runOnIoThread(Runnable runnable) {
         mIoHandler.post(runnable);
     }
@@ -367,21 +461,16 @@
         mControlHandler.post(runnable);
     }
 
-    private void init(HdmiControlService service, long nativePtr) {
-        mService = service;
-        mIoHandler = new Handler(service.getServiceLooper());
-        mControlHandler = new Handler(service.getServiceLooper());
-        mNativePtr = nativePtr;
-    }
-
     private boolean isAcceptableAddress(int address) {
-        // Can access command targeting devices available in local device or
-        // broadcast command.
-        return address == HdmiCec.ADDR_BROADCAST
-                || mLocalAddresses.indexOfKey(address) < 0;
+        // Can access command targeting devices available in local device or broadcast command.
+        if (address == HdmiCec.ADDR_BROADCAST) {
+            return true;
+        }
+        return isAllocatedLocalDeviceAddress(address);
     }
 
     private void onReceiveCommand(HdmiCecMessage message) {
+        assertRunOnServiceThread();
         if (isAcceptableAddress(message.getDestination()) &&
                 mService.handleCecCommand(message)) {
             return;
@@ -397,6 +486,10 @@
         sendCommand(cecMessage, null);
     }
 
+    void sendCommand(HdmiCecMessage cecMessage) {
+        sendCommand(cecMessage, null);
+    }
+
     void sendCommand(final HdmiCecMessage cecMessage,
             final HdmiControlService.SendMessageCallback callback) {
         runOnIoThread(new Runnable() {
@@ -405,6 +498,9 @@
                 byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                 final int error = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
                         cecMessage.getDestination(), body);
+                if (error != HdmiControlService.SEND_RESULT_SUCCESS) {
+                    Slog.w(TAG, "Failed to send " + cecMessage);
+                }
                 if (callback != null) {
                     runOnServiceThread(new Runnable() {
                         @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
new file mode 100644
index 0000000..e65e5fa
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -0,0 +1,103 @@
+/*
+ * 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 com.android.server.hdmi.HdmiCecController.AllocateLogicalAddressCallback;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+
+/**
+ * Class that models a logical CEC device hosted in this system. Handles initialization,
+ * CEC commands that call for actions customized per device type.
+ */
+abstract class HdmiCecLocalDevice {
+
+    protected final HdmiCecController mController;
+    protected final int mDeviceType;
+    protected int mAddress;
+    protected int mPreferredAddress;
+    protected HdmiCecDeviceInfo mDeviceInfo;
+
+    protected HdmiCecLocalDevice(HdmiCecController controller, int deviceType) {
+        mController = controller;
+        mDeviceType = deviceType;
+        mAddress = HdmiCec.ADDR_UNREGISTERED;
+    }
+
+    // Factory method that returns HdmiCecLocalDevice of corresponding type.
+    static HdmiCecLocalDevice create(HdmiCecController controller, int deviceType) {
+        switch (deviceType) {
+        case HdmiCec.DEVICE_TV:
+            return new HdmiCecLocalDeviceTv(controller);
+        case HdmiCec.DEVICE_PLAYBACK:
+            return new HdmiCecLocalDevicePlayback(controller);
+        default:
+            return null;
+        }
+    }
+
+    abstract void init();
+
+    protected void allocateAddress(int type) {
+        mController.allocateLogicalAddress(type, mPreferredAddress,
+                new AllocateLogicalAddressCallback() {
+            @Override
+            public void onAllocated(int deviceType, int logicalAddress) {
+                mAddress = mPreferredAddress = logicalAddress;
+
+                // Create and set device info.
+                HdmiCecDeviceInfo deviceInfo = createDeviceInfo(mAddress, deviceType);
+                setDeviceInfo(deviceInfo);
+                mController.addDeviceInfo(deviceInfo);
+
+                mController.addLogicalAddress(logicalAddress);
+            }
+        });
+    }
+
+    private final HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
+        int vendorId = mController.getVendorId();
+        int physicalAddress = mController.getPhysicalAddress();
+        // TODO: get device name read from system configuration.
+        String displayName = HdmiCec.getDefaultDeviceName(logicalAddress);
+        return new HdmiCecDeviceInfo(logicalAddress,
+                physicalAddress, deviceType, vendorId, displayName);
+    }
+
+    HdmiCecDeviceInfo getDeviceInfo() {
+        return mDeviceInfo;
+    }
+
+    void setDeviceInfo(HdmiCecDeviceInfo info) {
+        mDeviceInfo = info;
+    }
+
+    // Returns true if the logical address is same as the argument.
+    boolean isAddressOf(int addr) {
+        return addr == mAddress;
+    }
+
+    // Resets the logical address to unregistered(15), meaning the logical device is invalid.
+    void clearAddress() {
+        mAddress = HdmiCec.ADDR_UNREGISTERED;
+    }
+
+    void setPreferredAddress(int addr) {
+        mPreferredAddress = addr;
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
new file mode 100644
index 0000000..a953467
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -0,0 +1,36 @@
+/*
+ * 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 android.hardware.hdmi.HdmiCec;
+
+/**
+ * Represent a logical device of type Playback residing in Android system.
+ */
+final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
+
+    HdmiCecLocalDevicePlayback(HdmiCecController controller) {
+        super(controller, HdmiCec.DEVICE_PLAYBACK);
+    }
+
+    @Override
+    void init() {
+        allocateAddress(mDeviceType);
+        mController.sendCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+                mAddress, mController.getPhysicalAddress(), mDeviceType));
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
new file mode 100644
index 0000000..01ea685
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -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.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+
+/**
+ * Represent a logical device of type TV residing in Android system.
+ */
+final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
+
+    HdmiCecLocalDeviceTv(HdmiCecController controller) {
+        super(controller, HdmiCec.DEVICE_TV);
+    }
+
+    @Override
+    void init() {
+        allocateAddress(mDeviceType);
+
+        // TODO: vendor-specific initialization here.
+
+        mController.sendCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+                mAddress, mController.getPhysicalAddress(), mDeviceType));
+        mController.sendCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+                mAddress, mController.getVendorId()));
+
+        // TODO: Start routing control action, device discovery action.
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index d7a2c1c6..475852f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -37,6 +37,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -49,6 +50,10 @@
     // TODO: Rename the permission to HDMI_CONTROL.
     private static final String PERMISSION = "android.permission.HDMI_CEC";
 
+    static final int SEND_RESULT_SUCCESS = 0;
+    static final int SEND_RESULT_NAK = -1;
+    static final int SEND_RESULT_FAILURE = -2;
+
     /**
      * Interface to report send result.
      */
@@ -56,13 +61,26 @@
         /**
          * Called when {@link HdmiControlService#sendCecCommand} is completed.
          *
-         * @param error result of send request. 0 if succeed. Otherwise it will be
-         *        negative value
+         * @param error result of send request.
+         * @see {@link #SEND_RESULT_SUCCESS}
+         * @see {@link #SEND_RESULT_NAK}
+         * @see {@link #SEND_RESULT_FAILURE}
          */
-        // TODO: define error code as constants and update javadoc.
         void onSendCompleted(int error);
     }
 
+    /**
+     * Interface to get a list of available logical devices.
+     */
+    interface DevicePollingCallback {
+        /**
+         * Called when device polling is finished.
+         *
+         * @param ackedAddress a list of logical addresses of available devices
+         */
+        void onPollingFinished(List<Integer> ackedAddress);
+    }
+
     // A thread to handle synchronous IO of CEC and MHL control service.
     // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms)
     // and sparse call it shares a thread to handle IO operations.
@@ -160,6 +178,16 @@
         });
     }
 
+    // See if we have an action of a given type in progress.
+    private <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
+        for (FeatureAction action : mActions) {
+            if (action.getClass().equals(clazz)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Remove the given {@link FeatureAction} object from the action queue.
      *
@@ -276,6 +304,17 @@
         // TODO: Start "RequestArcInitiationAction" if ARC port.
     }
 
+    /**
+     * Poll all remote devices. It sends &lt;Polling Message&gt; to all remote
+     * devices.
+     *
+     * @param callback an interface used to get a list of all remote devices' address
+     * @param retryCount the number of retry used to send polling message to remote devices
+     */
+    void pollDevices(DevicePollingCallback callback, int retryCount) {
+        mCecController.pollDevices(callback, retryCount);
+    }
+
     private void handleInitiateArc(HdmiCecMessage message){
         // In case where <Initiate Arc> is started by <Request ARC Initiation>
         // need to clean up RequestArcInitiationAction.
@@ -386,36 +425,95 @@
         }
 
         @Override
-        public void oneTouchPlay(IHdmiControlCallback callback) {
+        public void oneTouchPlay(final IHdmiControlCallback callback) {
             enforceAccessPermission();
-            // TODO: Post a message for HdmiControlService#oneTouchPlay()
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiControlService.this.oneTouchPlay(callback);
+                }
+            });
         }
 
         @Override
-        public void queryDisplayStatus(IHdmiControlCallback callback) {
+        public void queryDisplayStatus(final IHdmiControlCallback callback) {
             enforceAccessPermission();
-            // TODO: Post a message for HdmiControlService#queryDisplayStatus()
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiControlService.this.queryDisplayStatus(callback);
+                }
+            });
         }
 
         @Override
-        public void addHotplugEventListener(IHdmiHotplugEventListener listener) {
+        public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
             enforceAccessPermission();
-            // TODO: Post a message for HdmiControlService#addHotplugEventListener()
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiControlService.this.addHotplugEventListener(listener);
+                }
+            });
         }
 
         @Override
-        public void removeHotplugEventListener(IHdmiHotplugEventListener listener) {
+        public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) {
             enforceAccessPermission();
-            // TODO: Post a message for HdmiControlService#removeHotplugEventListener()
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiControlService.this.removeHotplugEventListener(listener);
+                }
+            });
         }
     }
 
     private void oneTouchPlay(IHdmiControlCallback callback) {
-        // TODO: Create a new action
+        if (hasAction(OneTouchPlayAction.class)) {
+            Slog.w(TAG, "oneTouchPlay already in progress");
+            invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
+            return;
+        }
+        HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
+        if (source == null) {
+            Slog.w(TAG, "Local playback device not available");
+            invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+            return;
+        }
+        // TODO: Consider the case of multiple TV sets. For now we always direct the command
+        //       to the primary one.
+        OneTouchPlayAction action = OneTouchPlayAction.create(this,
+                source.getDeviceInfo().getLogicalAddress(),
+                source.getDeviceInfo().getPhysicalAddress(), HdmiCec.ADDR_TV, callback);
+        if (action == null) {
+            Slog.w(TAG, "Cannot initiate oneTouchPlay");
+            invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
+            return;
+        }
+        addAndStartAction(action);
     }
 
     private void queryDisplayStatus(IHdmiControlCallback callback) {
-        // TODO: Create a new action
+        if (hasAction(DevicePowerStatusAction.class)) {
+            Slog.w(TAG, "queryDisplayStatus already in progress");
+            invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
+            return;
+        }
+        HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
+        if (source == null) {
+            Slog.w(TAG, "Local playback device not available");
+            invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+            return;
+        }
+        DevicePowerStatusAction action = DevicePowerStatusAction.create(this,
+                source.getDeviceInfo().getLogicalAddress(), HdmiCec.ADDR_TV, callback);
+        if (action == null) {
+            Slog.w(TAG, "Cannot initiate queryDisplayStatus");
+            invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
+            return;
+        }
+        addAndStartAction(action);
     }
 
     private void addHotplugEventListener(IHdmiHotplugEventListener listener) {
@@ -444,4 +542,12 @@
             mHotplugEventListeners.remove(listener);
         }
     }
+
+    private void invokeCallback(IHdmiControlCallback callback, int result) {
+        try {
+            callback.onComplete(result);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Invoking callback failed:" + e);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
index db9d28d..343aff7 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
@@ -17,7 +17,6 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCecMessage;
-import android.util.Slog;
 
 /**
  * Feature action that handles ARC action initiated by TV devices.
@@ -43,12 +42,10 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                // success.
-                if (error == 0) {
+                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
                     mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
                     addTimer(mState, TIMEOUT_MS);
                 } else {
-                    Slog.w(TAG, "Failed to send <Request ARC Initiation>");
                     // If failed to send <Request ARC Initiation>, start "Disabled"
                     // ARC transmission action.
                     disableArcTransmission();
diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
index 7669f87..d4a35f8 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
@@ -17,7 +17,6 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCecMessage;
-import android.util.Slog;
 
 /**
  * Feature action to handle <Request ARC Termination>.
@@ -43,11 +42,10 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == 0) {
+                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
                     mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
                     addTimer(mState, TIMEOUT_MS);
                 } else {
-                    Slog.w(TAG, "Failed to send <Request ARC Initiation>");
                     // If failed to send <Request ARC Termination>, start "Disabled" ARC
                     // transmission action.
                     disableArcTransmission();
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index 94776a2..e3525d8 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -78,7 +78,7 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == 0) {
+                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
                     // Enable ARC status immediately after sending <Report Arc Initiated>.
                     // If AVR responds with <Feature Abort>, disable ARC status again.
                     // This is different from spec that says that turns ARC status to
@@ -94,9 +94,6 @@
                 } else {
                     // If fails to send <Report ARC Initiated>, disable ARC and
                     // send <Report ARC Terminated> directly.
-                    Slog.w(TAG, "Failed to send <Report ARC Initiated>:[source:"
-                            + mSourceAddress
-                            + ", avr Address:" + mAvrAddress + "]");
                     setArcStatus(false);
                     finish();
                 }
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index b94ea62..1b1fc8b 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -259,13 +259,17 @@
                     userIds[i]));
         }
 
-        ManagedServiceInfo[] toRemove = new ManagedServiceInfo[mServices.size()];
+        ArrayList<ManagedServiceInfo> toRemove = new ArrayList<ManagedServiceInfo>();
         final SparseArray<ArrayList<ComponentName>> toAdd
                 = new SparseArray<ArrayList<ComponentName>>();
 
         synchronized (mMutex) {
-            // unbind and remove all existing services
-            toRemove = mServices.toArray(toRemove);
+            // Unbind automatically bound services, retain system services.
+            for (ManagedServiceInfo service : mServices) {
+                if (!service.isSystem) {
+                    toRemove.add(service);
+                }
+            }
 
             final ArraySet<ComponentName> newEnabled = new ArraySet<ComponentName>();
             final ArraySet<String> newPackages = new ArraySet<String>();
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index d81a25e..009943f 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -46,12 +46,14 @@
  * {@hide}
  */
 public class NotificationUsageStats {
+    private static final boolean ENABLE_SQLITE_LOG = true;
+
     // Guarded by synchronized(this).
     private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
     private final SQLiteLog mSQLiteLog;
 
     public NotificationUsageStats(Context context) {
-        mSQLiteLog = new SQLiteLog(context);
+        mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null;
     }
 
     /**
@@ -63,7 +65,9 @@
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numPostedByApp++;
         }
-        mSQLiteLog.logPosted(notification);
+        if (ENABLE_SQLITE_LOG) {
+            mSQLiteLog.logPosted(notification);
+        }
     }
 
     /**
@@ -85,7 +89,9 @@
             stats.numRemovedByApp++;
             stats.collect(notification.stats);
         }
-        mSQLiteLog.logRemoved(notification);
+        if (ENABLE_SQLITE_LOG) {
+            mSQLiteLog.logRemoved(notification);
+        }
     }
 
     /**
@@ -97,7 +103,9 @@
             stats.numDismissedByUser++;
             stats.collect(notification.stats);
         }
-        mSQLiteLog.logDismissed(notification);
+        if (ENABLE_SQLITE_LOG) {
+            mSQLiteLog.logDismissed(notification);
+        }
     }
 
     /**
@@ -108,7 +116,9 @@
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numClickedByUser++;
         }
-        mSQLiteLog.logClicked(notification);
+        if (ENABLE_SQLITE_LOG) {
+            mSQLiteLog.logClicked(notification);
+        }
     }
 
     /**
@@ -164,7 +174,9 @@
         for (AggregatedStats as : mStats.values()) {
             as.dump(pw, indent);
         }
-        mSQLiteLog.dump(pw, indent);
+        if (ENABLE_SQLITE_LOG) {
+            mSQLiteLog.dump(pw, indent);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 157d749..a629a5f 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -139,56 +139,64 @@
     }
 
     private String[] getExtraPeople(Bundle extras) {
-        String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
-        if (people != null) {
-            return people;
+        Object people = extras.get(Notification.EXTRA_PEOPLE);
+        if (people instanceof String[]) {
+            return (String[]) people;
         }
 
-        ArrayList<String> stringArray = extras.getStringArrayList(Notification.EXTRA_PEOPLE);
-        if (stringArray != null) {
-            return (String[]) stringArray.toArray();
+        if (people instanceof ArrayList) {
+            ArrayList arrayList = (ArrayList) people;
+
+            if (arrayList.isEmpty()) {
+                return null;
+            }
+
+            if (arrayList.get(0) instanceof String) {
+                ArrayList<String> stringArray = (ArrayList<String>) arrayList;
+                return stringArray.toArray(new String[stringArray.size()]);
+            }
+
+            if (arrayList.get(0) instanceof CharSequence) {
+                ArrayList<CharSequence> charSeqList = (ArrayList<CharSequence>) arrayList;
+                final int N = charSeqList.size();
+                String[] array = new String[N];
+                for (int i = 0; i < N; i++) {
+                    array[i] = charSeqList.get(i).toString();
+                }
+                return array;
+            }
+
+            return null;
         }
 
-        String string = extras.getString(Notification.EXTRA_PEOPLE);
-        if (string != null) {
-            people = new String[1];
-            people[0] = string;
-            return people;
-        }
-        char[] charArray = extras.getCharArray(Notification.EXTRA_PEOPLE);
-        if (charArray != null) {
-            people = new String[1];
-            people[0] = new String(charArray);
-            return people;
+        if (people instanceof String) {
+            String[] array = new String[1];
+            array[0] = (String) people;
+            return array;
         }
 
-        CharSequence charSeq = extras.getCharSequence(Notification.EXTRA_PEOPLE);
-        if (charSeq != null) {
-            people = new String[1];
-            people[0] = charSeq.toString();
-            return people;
+        if (people instanceof char[]) {
+            String[] array = new String[1];
+            array[0] = new String((char[]) people);
+            return array;
         }
 
-        CharSequence[] charSeqArray = extras.getCharSequenceArray(Notification.EXTRA_PEOPLE);
-        if (charSeqArray != null) {
+        if (people instanceof CharSequence) {
+            String[] array = new String[1];
+            array[0] = ((CharSequence) people).toString();
+            return array;
+        }
+
+        if (people instanceof CharSequence[]) {
+            CharSequence[] charSeqArray = (CharSequence[]) people;
             final int N = charSeqArray.length;
-            people = new String[N];
+            String[] array = new String[N];
             for (int i = 0; i < N; i++) {
-                people[i] = charSeqArray[i].toString();
+                array[i] = charSeqArray[i].toString();
             }
-            return people;
+            return array;
         }
 
-        ArrayList<CharSequence> charSeqList =
-                extras.getCharSequenceArrayList(Notification.EXTRA_PEOPLE);
-        if (charSeqList != null) {
-            final int N = charSeqList.size();
-            people = new String[N];
-            for (int i = 0; i < N; i++) {
-                people[i] = charSeqList.get(i).toString();
-            }
-            return people;
-        }
         return null;
     }
 
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
new file mode 100644
index 0000000..3d432dc
--- /dev/null
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
@@ -0,0 +1,118 @@
+/*
+ * 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 com.android.server.pm;
+
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import android.content.IntentFilter;
+import android.util.Log;
+import java.io.IOException;
+import android.os.UserHandle;
+
+/**
+ * The {@link PackageManagerService} maintains some {@link CrossProfileIntentFilter}s for each user.
+ * If an {@link Intent} matches the {@link CrossProfileIntentFilter}, then activities in the user
+ * {@link #mTargetUserId} can access it.
+ */
+class CrossProfileIntentFilter extends IntentFilter {
+    private static final String ATTR_TARGET_USER_ID = "targetUserId";
+    private static final String ATTR_USER_ID_DEST = "userIdDest";//Old name. Kept for compatibility.
+    private static final String ATTR_REMOVABLE = "removable";
+    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;
+    boolean mRemovable;
+
+    CrossProfileIntentFilter(IntentFilter filter, boolean removable, int targetUserId) {
+        super(filter);
+        mTargetUserId = targetUserId;
+        mRemovable = removable;
+    }
+
+    public int getTargetUserId() {
+        return mTargetUserId;
+    }
+
+    public boolean isRemovable() {
+        return mRemovable;
+    }
+
+    CrossProfileIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
+        String targetUserIdString = parser.getAttributeValue(null, ATTR_TARGET_USER_ID);
+        if (targetUserIdString == null) {
+            targetUserIdString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
+        }
+        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 removableString = parser.getAttributeValue(null, ATTR_REMOVABLE);
+        if (removableString != null) {
+            mRemovable = Boolean.parseBoolean(removableString);
+        }
+        int outerDepth = parser.getDepth();
+        String tagName = parser.getName();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            tagName = parser.getName();
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            } else if (type == XmlPullParser.START_TAG) {
+                if (tagName.equals(ATTR_FILTER)) {
+                    break;
+                } else {
+                    String msg = "Unknown element under " + Settings.TAG_FORWARDING_INTENT_FILTERS
+                            + ": " + tagName + " at " + parser.getPositionDescription();
+                    PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+        }
+        if (tagName.equals(ATTR_FILTER)) {
+            readFromXml(parser);
+        } else {
+            String msg = "Missing element under " + TAG + ": " + ATTR_FILTER +
+                    " at " + parser.getPositionDescription();
+            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+
+    public void writeToXml(XmlSerializer serializer) throws IOException {
+        serializer.attribute(null, ATTR_TARGET_USER_ID, Integer.toString(mTargetUserId));
+        serializer.attribute(null, ATTR_REMOVABLE, Boolean.toString(mRemovable));
+        serializer.startTag(null, ATTR_FILTER);
+            super.writeToXml(serializer);
+        serializer.endTag(null, ATTR_FILTER);
+    }
+
+    @Override
+    public String toString() {
+        return "CrossProfileIntentFilter{0x" + Integer.toHexString(System.identityHashCode(this))
+                + " " + Integer.toString(mTargetUserId) + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
new file mode 100644
index 0000000..a335d3a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.android.server.pm;
+
+
+import java.io.PrintWriter;
+import com.android.server.IntentResolver;
+import java.util.List;
+
+/**
+ * Used to find a list of {@link CrossProfileIntentFilter}s that match an intent.
+ */
+class CrossProfileIntentResolver
+        extends IntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter> {
+    @Override
+    protected CrossProfileIntentFilter[] newArray(int size) {
+        return new CrossProfileIntentFilter[size];
+    }
+
+    @Override
+    protected boolean isPackageForFilter(String packageName, CrossProfileIntentFilter filter) {
+        return false;
+    }
+
+    @Override
+    protected void sortResults(List<CrossProfileIntentFilter> results) {
+        //We don't sort the results
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
deleted file mode 100644
index 85bde98..0000000
--- a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
+++ /dev/null
@@ -1,114 +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 com.android.server.pm;
-
-import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-import android.content.IntentFilter;
-import android.util.Log;
-import java.io.IOException;
-import android.os.UserHandle;
-
-/**
- * The {@link PackageManagerService} maintains some {@link ForwardingIntentFilter}s for every user.
- * If an {@link Intent} matches the {@link ForwardingIntentFilter}, then it can be forwarded to the
- * {@link #mUserIdDest}.
- */
-class ForwardingIntentFilter extends IntentFilter {
-    private static final String ATTR_USER_ID_DEST = "userIdDest";
-    private static final String ATTR_REMOVABLE = "removable";
-    private static final String ATTR_FILTER = "filter";
-
-    private static final String TAG = "ForwardingIntentFilter";
-
-    // If the intent matches the IntentFilter, then it can be forwarded to this userId.
-    final int mUserIdDest;
-    boolean mRemovable;
-
-    ForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdDest) {
-        super(filter);
-        mUserIdDest = userIdDest;
-        mRemovable = removable;
-    }
-
-    public int getUserIdDest() {
-        return mUserIdDest;
-    }
-
-    public boolean isRemovable() {
-        return mRemovable;
-    }
-
-    ForwardingIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
-        String userIdDestString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
-        if (userIdDestString == null) {
-            String msg = "Missing element under " + TAG +": " + ATTR_USER_ID_DEST + " at " +
-                    parser.getPositionDescription();
-            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
-            mUserIdDest = UserHandle.USER_NULL;
-        } else {
-            mUserIdDest = Integer.parseInt(userIdDestString);
-        }
-        String removableString = parser.getAttributeValue(null, ATTR_REMOVABLE);
-        if (removableString != null) {
-            mRemovable = Boolean.parseBoolean(removableString);
-        }
-        int outerDepth = parser.getDepth();
-        String tagName = parser.getName();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            tagName = parser.getName();
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            } else if (type == XmlPullParser.START_TAG) {
-                if (tagName.equals(ATTR_FILTER)) {
-                    break;
-                } else {
-                    String msg = "Unknown element under " + Settings.TAG_FORWARDING_INTENT_FILTERS
-                            + ": " + tagName + " at " + parser.getPositionDescription();
-                    PackageManagerService.reportSettingsProblem(Log.WARN, msg);
-                    XmlUtils.skipCurrentTag(parser);
-                }
-            }
-        }
-        if (tagName.equals(ATTR_FILTER)) {
-            readFromXml(parser);
-        } else {
-            String msg = "Missing element under " + TAG + ": " + ATTR_FILTER +
-                    " at " + parser.getPositionDescription();
-            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
-            XmlUtils.skipCurrentTag(parser);
-        }
-    }
-
-    public void writeToXml(XmlSerializer serializer) throws IOException {
-        serializer.attribute(null, ATTR_USER_ID_DEST, Integer.toString(mUserIdDest));
-        serializer.attribute(null, ATTR_REMOVABLE, Boolean.toString(mRemovable));
-        serializer.startTag(null, ATTR_FILTER);
-            super.writeToXml(serializer);
-        serializer.endTag(null, ATTR_FILTER);
-    }
-
-    @Override
-    public String toString() {
-        return "ForwardingIntentFilter{0x" + Integer.toHexString(System.identityHashCode(this))
-                + " " + Integer.toString(mUserIdDest) + "}";
-    }
-}
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentResolver.java b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
deleted file mode 100644
index 1616395..0000000
--- a/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
+++ /dev/null
@@ -1,44 +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 com.android.server.pm;
-
-
-import java.io.PrintWriter;
-import com.android.server.IntentResolver;
-import java.util.List;
-
-/**
- * Used to find a list of {@link ForwardingIntentFilter}s that match an intent.
- */
-class ForwardingIntentResolver
-        extends IntentResolver<ForwardingIntentFilter, ForwardingIntentFilter> {
-    @Override
-    protected ForwardingIntentFilter[] newArray(int size) {
-        return new ForwardingIntentFilter[size];
-    }
-
-    @Override
-    protected boolean isPackageForFilter(String packageName, ForwardingIntentFilter filter) {
-        return false;
-    }
-
-    @Override
-    protected void sortResults(List<ForwardingIntentFilter> results) {
-        //We don't sort the results
-    }
-}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b06b090..6d75ee5 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3374,25 +3374,26 @@
      * Returns if intent can be forwarded from the userId from to dest
      */
     @Override
-    public boolean canForwardTo(Intent intent, String resolvedType, int userIdFrom, int userIdDest) {
+    public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId,
+            int targetUserId) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        List<ForwardingIntentFilter> matches =
-                getMatchingForwardingIntentFilters(intent, resolvedType, userIdFrom);
+        List<CrossProfileIntentFilter> matches =
+                getMatchingCrossProfileIntentFilters(intent, resolvedType, sourceUserId);
         if (matches != null) {
             int size = matches.size();
             for (int i = 0; i < size; i++) {
-                if (matches.get(i).getUserIdDest() == userIdDest) return true;
+                if (matches.get(i).getTargetUserId() == targetUserId) return true;
             }
         }
         return false;
     }
 
-    private List<ForwardingIntentFilter> getMatchingForwardingIntentFilters(Intent intent,
+    private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
             String resolvedType, int userId) {
-        ForwardingIntentResolver fir = mSettings.mForwardingIntentResolvers.get(userId);
-        if (fir != null) {
-            return fir.queryIntent(intent, resolvedType, false, userId);
+        CrossProfileIntentResolver cpir = mSettings.mCrossProfileIntentResolvers.get(userId);
+        if (cpir != null) {
+            return cpir.queryIntent(intent, resolvedType, false, userId);
         }
         return null;
     }
@@ -3428,31 +3429,31 @@
                 List<ResolveInfo> result =
                         mActivities.queryIntent(intent, resolvedType, flags, userId);
                 // Checking if we can forward the intent to another user
-                List<ForwardingIntentFilter> fifs =
-                        getMatchingForwardingIntentFilters(intent, resolvedType, userId);
-                if (fifs != null) {
-                    ForwardingIntentFilter forwardingIntentFilterWithResult = null;
+                List<CrossProfileIntentFilter> cpifs =
+                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
+                if (cpifs != null) {
+                    CrossProfileIntentFilter crossProfileIntentFilterWithResult = null;
                     HashSet<Integer> alreadyTriedUserIds = new HashSet<Integer>();
-                    for (ForwardingIntentFilter fif : fifs) {
-                        int userIdDest = fif.getUserIdDest();
-                        // Two {@link ForwardingIntentFilter}s can have the same userIdDest and
+                    for (CrossProfileIntentFilter cpif : cpifs) {
+                        int targetUserId = cpif.getTargetUserId();
+                        // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
                         // match the same an intent. For performance reasons, it is better not to
                         // run queryIntent twice for the same userId
-                        if (!alreadyTriedUserIds.contains(userIdDest)) {
+                        if (!alreadyTriedUserIds.contains(targetUserId)) {
                             List<ResolveInfo> resultUser = mActivities.queryIntent(intent,
-                                    resolvedType, flags, userIdDest);
+                                    resolvedType, flags, targetUserId);
                             if (resultUser != null) {
-                                forwardingIntentFilterWithResult = fif;
+                                crossProfileIntentFilterWithResult = cpif;
                                 // As soon as there is a match in another user, we add the
                                 // intentForwarderActivity to the list of ResolveInfo.
                                 break;
                             }
-                            alreadyTriedUserIds.add(userIdDest);
+                            alreadyTriedUserIds.add(targetUserId);
                         }
                     }
-                    if (forwardingIntentFilterWithResult != null) {
+                    if (crossProfileIntentFilterWithResult != null) {
                         ResolveInfo forwardingResolveInfo = createForwardingResolveInfo(
-                                forwardingIntentFilterWithResult, userId);
+                                crossProfileIntentFilterWithResult, userId);
                         result.add(forwardingResolveInfo);
                     }
                 }
@@ -3467,10 +3468,11 @@
         }
     }
 
-    private ResolveInfo createForwardingResolveInfo(ForwardingIntentFilter fif, int userIdFrom) {
+    private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter cpif,
+            int sourceUserId) {
         String className;
-        int userIdDest = fif.getUserIdDest();
-        if (userIdDest == UserHandle.USER_OWNER) {
+        int targetUserId = cpif.getTargetUserId();
+        if (targetUserId == UserHandle.USER_OWNER) {
             className = FORWARD_INTENT_TO_USER_OWNER;
         } else {
             className = FORWARD_INTENT_TO_MANAGED_PROFILE;
@@ -3478,14 +3480,14 @@
         ComponentName forwardingActivityComponentName = new ComponentName(
                 mAndroidApplication.packageName, className);
         ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0,
-                userIdFrom);
+                sourceUserId);
         ResolveInfo forwardingResolveInfo = new ResolveInfo();
         forwardingResolveInfo.activityInfo = forwardingActivityInfo;
         forwardingResolveInfo.priority = 0;
         forwardingResolveInfo.preferredOrder = 0;
         forwardingResolveInfo.match = 0;
         forwardingResolveInfo.isDefault = true;
-        forwardingResolveInfo.filter = fif;
+        forwardingResolveInfo.filter = cpif;
         return forwardingResolveInfo;
     }
 
@@ -11475,33 +11477,34 @@
     }
 
     @Override
-    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
-            int userIdDest) {
+    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
+            int sourceUserId, int targetUserId) {
         mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         if (filter.countActions() == 0) {
-            Slog.w(TAG, "Cannot set a forwarding intent filter with no filter actions");
+            Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
             return;
         }
         synchronized (mPackages) {
-            mSettings.editForwardingIntentResolverLPw(userIdOrig).addFilter(
-                    new ForwardingIntentFilter(filter, removable, userIdDest));
-            mSettings.writePackageRestrictionsLPr(userIdOrig);
+            mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(
+                    new CrossProfileIntentFilter(filter, removable, targetUserId));
+            mSettings.writePackageRestrictionsLPr(sourceUserId);
         }
     }
 
     @Override
-    public void clearForwardingIntentFilters(int userIdOrig) {
+    public void clearCrossProfileIntentFilters(int sourceUserId) {
         mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         synchronized (mPackages) {
-            ForwardingIntentResolver fir = mSettings.editForwardingIntentResolverLPw(userIdOrig);
-            HashSet<ForwardingIntentFilter> set =
-                    new HashSet<ForwardingIntentFilter>(fir.filterSet());
-            for (ForwardingIntentFilter fif : set) {
-                if (fif.isRemovable()) fir.removeFilter(fif);
+            CrossProfileIntentResolver cpir =
+                    mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
+            HashSet<CrossProfileIntentFilter> set =
+                    new HashSet<CrossProfileIntentFilter>(cpir.filterSet());
+            for (CrossProfileIntentFilter cpif : set) {
+                if (cpif.isRemovable()) cpir.removeFilter(cpif);
             }
-            mSettings.writePackageRestrictionsLPr(userIdOrig);
+            mSettings.writePackageRestrictionsLPr(sourceUserId);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 3ca658f..bb92611 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -132,6 +132,9 @@
     private static final String TAG_PACKAGE = "pkg";
     private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
             "persistent-preferred-activities";
+    static final String TAG_CROSS_PROFILE_INTENT_FILTERS =
+            "crossProfile-intent-filters";
+    //Old name. Kept for compatibility
     static final String TAG_FORWARDING_INTENT_FILTERS =
             "forwarding-intent-filters";
 
@@ -189,8 +192,8 @@
             new SparseArray<PersistentPreferredIntentResolver>();
 
     // For every user, it is used to find to which other users the intent can be forwarded.
-    final SparseArray<ForwardingIntentResolver> mForwardingIntentResolvers =
-            new SparseArray<ForwardingIntentResolver>();
+    final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
+            new SparseArray<CrossProfileIntentResolver>();
 
     final HashMap<String, SharedUserSetting> mSharedUsers =
             new HashMap<String, SharedUserSetting>();
@@ -856,13 +859,13 @@
         return ppir;
     }
 
-    ForwardingIntentResolver editForwardingIntentResolverLPw(int userId) {
-        ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
-        if (fir == null) {
-            fir = new ForwardingIntentResolver();
-            mForwardingIntentResolvers.put(userId, fir);
+    CrossProfileIntentResolver editCrossProfileIntentResolverLPw(int userId) {
+        CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(userId);
+        if (cpir == null) {
+            cpir = new CrossProfileIntentResolver();
+            mCrossProfileIntentResolvers.put(userId, cpir);
         }
-        return fir;
+        return cpir;
     }
 
     private File getUserPackagesStateFile(int userId) {
@@ -980,7 +983,7 @@
         }
     }
 
-    private void readForwardingIntentFiltersLPw(XmlPullParser parser, int userId)
+    private void readCrossProfileIntentFiltersLPw(XmlPullParser parser, int userId)
             throws XmlPullParserException, IOException {
         int outerDepth = parser.getDepth();
         int type;
@@ -991,10 +994,10 @@
             }
             String tagName = parser.getName();
             if (tagName.equals(TAG_ITEM)) {
-                ForwardingIntentFilter fif = new ForwardingIntentFilter(parser);
-                editForwardingIntentResolverLPw(userId).addFilter(fif);
+                CrossProfileIntentFilter cpif = new CrossProfileIntentFilter(parser);
+                editCrossProfileIntentResolverLPw(userId).addFilter(cpif);
             } else {
-                String msg = "Unknown element under " +  TAG_FORWARDING_INTENT_FILTERS + ": " +
+                String msg = "Unknown element under " +  TAG_CROSS_PROFILE_INTENT_FILTERS + ": " +
                         parser.getName();
                 PackageManagerService.reportSettingsProblem(Log.WARN, msg);
                 XmlUtils.skipCurrentTag(parser);
@@ -1130,8 +1133,9 @@
                     readPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
                     readPersistentPreferredActivitiesLPw(parser, userId);
-                } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
-                    readForwardingIntentFiltersLPw(parser, userId);
+                } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)
+                        || tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
+                    readCrossProfileIntentFiltersLPw(parser, userId);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -1209,18 +1213,18 @@
         serializer.endTag(null, TAG_PERSISTENT_PREFERRED_ACTIVITIES);
     }
 
-    void writeForwardingIntentFiltersLPr(XmlSerializer serializer, int userId)
+    void writeCrossProfileIntentFiltersLPr(XmlSerializer serializer, int userId)
             throws IllegalArgumentException, IllegalStateException, IOException {
-        serializer.startTag(null, TAG_FORWARDING_INTENT_FILTERS);
-        ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
-        if (fir != null) {
-            for (final ForwardingIntentFilter fif : fir.filterSet()) {
+        serializer.startTag(null, TAG_CROSS_PROFILE_INTENT_FILTERS);
+        CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(userId);
+        if (cpir != null) {
+            for (final CrossProfileIntentFilter cpif : cpir.filterSet()) {
                 serializer.startTag(null, TAG_ITEM);
-                fif.writeToXml(serializer);
+                cpif.writeToXml(serializer);
                 serializer.endTag(null, TAG_ITEM);
             }
         }
-        serializer.endTag(null, TAG_FORWARDING_INTENT_FILTERS);
+        serializer.endTag(null, TAG_CROSS_PROFILE_INTENT_FILTERS);
     }
 
     void writePackageRestrictionsLPr(int userId) {
@@ -1321,7 +1325,7 @@
 
             writePersistentPreferredActivitiesLPr(serializer, userId);
 
-            writeForwardingIntentFiltersLPr(serializer, userId);
+            writeCrossProfileIntentFiltersLPr(serializer, userId);
 
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
@@ -1943,7 +1947,7 @@
                 } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
                     // TODO: check whether this is okay! as it is very
                     // similar to how preferred-activities are treated
-                    readForwardingIntentFiltersLPw(parser, 0);
+                    readCrossProfileIntentFiltersLPw(parser, 0);
                 } else if (tagName.equals("updated-package")) {
                     readDisabledSysPackageLPw(parser);
                 } else if (tagName.equals("cleaning-package")) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 102b2d4..1bf40e0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1140,53 +1140,57 @@
      */
     public boolean removeUser(int userHandle) {
         checkManageUsersPermission("Only the system can remove users");
-        final UserInfo user;
-        synchronized (mPackagesLock) {
-            user = mUsers.get(userHandle);
-            if (userHandle == 0 || user == null) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            final UserInfo user;
+            synchronized (mPackagesLock) {
+                user = mUsers.get(userHandle);
+                if (userHandle == 0 || user == null) {
+                    return false;
+                }
+                mRemovingUserIds.put(userHandle, true);
+                try {
+                    mAppOpsService.removeUser(userHandle);
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
+                }
+                // Set this to a partially created user, so that the user will be purged
+                // on next startup, in case the runtime stops now before stopping and
+                // removing the user completely.
+                user.partial = true;
+                // Mark it as disabled, so that it isn't returned any more when
+                // profiles are queried.
+                user.flags |= UserInfo.FLAG_DISABLED;
+                writeUserLocked(user);
+            }
+
+            if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+                    && user.isManagedProfile()) {
+                // Send broadcast to notify system that the user removed was a
+                // managed user.
+                sendProfileRemovedBroadcast(user.profileGroupId, user.id);
+            }
+
+            if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
+            int res;
+            try {
+                res = ActivityManagerNative.getDefault().stopUser(userHandle,
+                        new IStopUserCallback.Stub() {
+                            @Override
+                            public void userStopped(int userId) {
+                                finishRemoveUser(userId);
+                            }
+                            @Override
+                            public void userStopAborted(int userId) {
+                            }
+                        });
+            } catch (RemoteException e) {
                 return false;
             }
-            mRemovingUserIds.put(userHandle, true);
-            try {
-                mAppOpsService.removeUser(userHandle);
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
-            }
-            // Set this to a partially created user, so that the user will be purged
-            // on next startup, in case the runtime stops now before stopping and
-            // removing the user completely.
-            user.partial = true;
-            // Mark it as disabled, so that it isn't returned any more when
-            // profiles are queried.
-            user.flags |= UserInfo.FLAG_DISABLED;
-            writeUserLocked(user);
+            return res == ActivityManager.USER_OP_SUCCESS;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
-
-        if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
-                && user.isManagedProfile()) {
-            // Send broadcast to notify system that the user removed was a
-            // managed user.
-            sendProfileRemovedBroadcast(user.profileGroupId, user.id);
-        }
-
-        if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
-        int res;
-        try {
-            res = ActivityManagerNative.getDefault().stopUser(userHandle,
-                    new IStopUserCallback.Stub() {
-                        @Override
-                        public void userStopped(int userId) {
-                            finishRemoveUser(userId);
-                        }
-                        @Override
-                        public void userStopAborted(int userId) {
-                        }
-            });
-        } catch (RemoteException e) {
-            return false;
-        }
-
-        return res == ActivityManager.USER_OP_SUCCESS;
     }
 
     void finishRemoveUser(final int userHandle) {
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
index db2d4ee..b1a4636 100644
--- a/services/core/java/com/android/server/task/StateChangedListener.java
+++ b/services/core/java/com/android/server/task/StateChangedListener.java
@@ -27,9 +27,8 @@
     /**
      * Called by the controller to notify the TaskManager that it should check on the state of a
      * task.
-     * @param taskStatus The state of the task which has changed.
      */
-    public void onTaskStateChanged(TaskStatus taskStatus);
+    public void onControllerStateChanged();
 
     /**
      * Called by the controller to notify the TaskManager that regardless of the state of the task,
diff --git a/services/core/java/com/android/server/task/TaskCompletedListener.java b/services/core/java/com/android/server/task/TaskCompletedListener.java
index 0210442..c53f5ca 100644
--- a/services/core/java/com/android/server/task/TaskCompletedListener.java
+++ b/services/core/java/com/android/server/task/TaskCompletedListener.java
@@ -16,6 +16,8 @@
 
 package com.android.server.task;
 
+import com.android.server.task.controllers.TaskStatus;
+
 /**
  * Used for communication between {@link com.android.server.task.TaskServiceContext} and the
  * {@link com.android.server.task.TaskManagerService}.
@@ -26,13 +28,5 @@
      * Callback for when a task is completed.
      * @param needsReschedule Whether the implementing class should reschedule this task.
      */
-    public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule);
-
-    /**
-     * Callback for when the implementing class needs to clean up the
-     * {@link com.android.server.task.TaskServiceContext}. The scheduler can get this callback
-     * several times if the TaskServiceContext got into a bad state (for e.g. the client crashed
-     * and it needs to clean up).
-     */
-    public void onAllTasksCompleted(int serviceToken);
+    public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule);
 }
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
index 6d208ff..d5b70e6 100644
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -16,15 +16,33 @@
 
 package com.android.server.task;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import android.app.task.ITaskManager;
+import android.app.task.Task;
+import android.app.task.TaskManager;
 import android.content.Context;
-import android.content.Task;
+import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.util.Log;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.server.task.controllers.ConnectivityController;
+import com.android.server.task.controllers.IdleController;
+import com.android.server.task.controllers.StateController;
 import com.android.server.task.controllers.TaskStatus;
+import com.android.server.task.controllers.TimeController;
+
+import java.util.LinkedList;
 
 /**
  * Responsible for taking tasks representing work to be performed by a client app, and determining
@@ -34,78 +52,151 @@
  */
 public class TaskManagerService extends com.android.server.SystemService
         implements StateChangedListener, TaskCompletedListener {
+    // TODO: Switch this off for final version.
+    private static final boolean DEBUG = true;
+    /** The number of concurrent tasks we run at one time. */
+    private static final int MAX_TASK_CONTEXTS_COUNT = 3;
     static final String TAG = "TaskManager";
+    /**
+     * When a task fails, it gets rescheduled according to its backoff policy. To be nice, we allow
+     * this amount of time from the rescheduled time by which the retry must occur.
+     */
+    private static final long RESCHEDULE_WINDOW_SLOP_MILLIS = 5000L;
 
     /** Master list of tasks. */
     private final TaskStore mTasks;
 
-    /** Check the pending queue and start any tasks. */
-    static final int MSG_RUN_PENDING = 0;
-    /** Initiate the stop task flow. */
-    static final int MSG_STOP_TASK = 1;
-    /** */
-    static final int MSG_CHECK_TASKS = 2;
+    static final int MSG_TASK_EXPIRED = 0;
+    static final int MSG_CHECK_TASKS = 1;
+
+    // Policy constants
+    /**
+     * Minimum # of idle tasks that must be ready in order to force the TM to schedule things
+     * early.
+     */
+    private static final int MIN_IDLE_COUNT = 1;
+    /**
+     * Minimum # of connectivity tasks that must be ready in order to force the TM to schedule
+     * things early.
+     */
+    private static final int MIN_CONNECTIVITY_COUNT = 2;
+    /**
+     * Minimum # of tasks (with no particular constraints) for which the TM will be happy running
+     * some work early.
+     */
+    private static final int MIN_READY_TASKS_COUNT = 4;
 
     /**
      * Track Services that have currently active or pending tasks. The index is provided by
      * {@link TaskStatus#getServiceToken()}
      */
-    private final SparseArray<TaskServiceContext> mActiveServices =
-            new SparseArray<TaskServiceContext>();
+    private final List<TaskServiceContext> mActiveServices = new LinkedList<TaskServiceContext>();
+    /** List of controllers that will notify this service of updates to tasks. */
+    private List<StateController> mControllers;
+    /**
+     * Queue of pending tasks. The TaskServiceContext class will receive tasks from this list
+     * when ready to execute them.
+     */
+    private final LinkedList<TaskStatus> mPendingTasks = new LinkedList<TaskStatus>();
 
     private final TaskHandler mHandler;
+    private final TaskManagerStub mTaskManagerStub;
 
-    private class TaskHandler extends Handler {
+    /**
+     * Entry point from client to schedule the provided task.
+     * This will add the task to the
+     * @param task Task object containing execution parameters
+     * @param uId The package identifier of the application this task is for.
+     * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
+     *                    of this task.
+     * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+     */
+    public int schedule(Task task, int uId, boolean canPersistTask) {
+        TaskStatus taskStatus = new TaskStatus(task, uId, canPersistTask);
+        return startTrackingTask(taskStatus) ?
+                TaskManager.RESULT_SUCCESS : TaskManager.RESULT_FAILURE;
+    }
 
-        public TaskHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message message) {
-            switch (message.what) {
-                case MSG_RUN_PENDING:
-
-                    break;
-                case MSG_STOP_TASK:
-
-                    break;
-                case MSG_CHECK_TASKS:
-                    checkTasks();
-                    break;
+    public List<Task> getPendingTasks(int uid) {
+        ArrayList<Task> outList = new ArrayList<Task>();
+        synchronized (mTasks) {
+            for (TaskStatus ts : mTasks.getTasks()) {
+                if (ts.getUid() == uid) {
+                    outList.add(ts.getTask());
+                }
             }
         }
+        return outList;
+    }
 
-        /**
-         * Called when we need to run through the list of all tasks and start/stop executing one or
-         * more of them.
-         */
-        private void checkTasks() {
-            synchronized (mTasks) {
-                final SparseArray<TaskStatus> tasks = mTasks.getTasks();
-                for (int i = 0; i < tasks.size(); i++) {
-                    TaskStatus ts = tasks.valueAt(i);
-                    if (ts.isReady() && ! isCurrentlyActive(ts)) {
-                        assignTaskToServiceContext(ts);
-                    }
+    /**
+     * Entry point from client to cancel all tasks originating from their uid.
+     * This will remove the task from the master list, and cancel the task if it was staged for
+     * execution or being executed.
+     * @param uid To check against for removal of a task.
+     */
+    public void cancelTaskForUid(int uid) {
+        // Remove from master list.
+        synchronized (mTasks) {
+            if (!mTasks.removeAllByUid(uid)) {
+                // If it's not in the master list, it's nowhere.
+                return;
+            }
+        }
+        // Remove from pending queue.
+        synchronized (mPendingTasks) {
+            Iterator<TaskStatus> it = mPendingTasks.iterator();
+            while (it.hasNext()) {
+                TaskStatus ts = it.next();
+                if (ts.getUid() == uid) {
+                    it.remove();
+                }
+            }
+        }
+        // Cancel if running.
+        synchronized (mActiveServices) {
+            for (TaskServiceContext tsc : mActiveServices) {
+                if (tsc.getRunningTask().getUid() == uid) {
+                    tsc.cancelExecutingTask();
                 }
             }
         }
     }
 
     /**
-     * Entry point from client to schedule the provided task.
-     * This will add the task to the
-     * @param task Task object containing execution parameters
-     * @param userId The id of the user this task is for.
-     * @param uId The package identifier of the application this task is for.
-     * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
-     *                    of this task.
-     * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+     * Entry point from client to cancel the task corresponding to the taskId provided.
+     * This will remove the task from the master list, and cancel the task if it was staged for
+     * execution or being executed.
+     * @param uid Uid of the calling client.
+     * @param taskId Id of the task, provided at schedule-time.
      */
-    public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
-        TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
-        return 0;
+    public void cancelTask(int uid, int taskId) {
+        synchronized (mTasks) {
+            if (!mTasks.remove(uid, taskId)) {
+                // If it's not in the master list, it's nowhere.
+                return;
+            }
+        }
+        synchronized (mPendingTasks) {
+            Iterator<TaskStatus> it = mPendingTasks.iterator();
+            while (it.hasNext()) {
+                TaskStatus ts = it.next();
+                if (ts.getUid() == uid && ts.getTaskId() == taskId) {
+                    it.remove();
+                    // If we got it from pending, it didn't make it to active so return.
+                    return;
+                }
+            }
+        }
+        synchronized (mActiveServices) {
+            for (TaskServiceContext tsc : mActiveServices) {
+                if (tsc.getRunningTask().getUid() == uid &&
+                        tsc.getRunningTask().getTaskId() == taskId) {
+                    tsc.cancelExecutingTask();
+                    return;
+                }
+            }
+        }
     }
 
     /**
@@ -121,11 +212,176 @@
         super(context);
         mTasks = new TaskStore(context);
         mHandler = new TaskHandler(context.getMainLooper());
+        mTaskManagerStub = new TaskManagerStub();
+        // Create the "runners".
+        for (int i = 0; i < MAX_TASK_CONTEXTS_COUNT; i++) {
+            mActiveServices.add(
+                    new TaskServiceContext(this, context.getMainLooper()));
+        }
+
+        mControllers = new LinkedList<StateController>();
+        mControllers.add(ConnectivityController.get(this));
+        mControllers.add(TimeController.get(this));
+        mControllers.add(IdleController.get(this));
+        // TODO: Add BatteryStateController when implemented.
     }
 
     @Override
     public void onStart() {
+        publishBinderService(Context.TASK_SERVICE, mTaskManagerStub);
+    }
 
+    /**
+     * Called when we have a task status object that we need to insert in our
+     * {@link com.android.server.task.TaskStore}, and make sure all the relevant controllers know
+     * about.
+     */
+    private boolean startTrackingTask(TaskStatus taskStatus) {
+        boolean added = false;
+        synchronized (mTasks) {
+            added = mTasks.add(taskStatus);
+        }
+        if (added) {
+            for (StateController controller : mControllers) {
+                controller.maybeStartTrackingTask(taskStatus);
+            }
+        }
+        return added;
+    }
+
+    /**
+     * Called when we want to remove a TaskStatus object that we've finished executing. Returns the
+     * object removed.
+     */
+    private boolean stopTrackingTask(TaskStatus taskStatus) {
+        boolean removed;
+        synchronized (mTasks) {
+            // Remove from store as well as controllers.
+            removed = mTasks.remove(taskStatus);
+        }
+        if (removed) {
+            for (StateController controller : mControllers) {
+                controller.maybeStopTrackingTask(taskStatus);
+            }
+        }
+        return removed;
+    }
+
+    private boolean cancelTaskOnServiceContext(TaskStatus ts) {
+        synchronized (mActiveServices) {
+            for (TaskServiceContext tsc : mActiveServices) {
+                if (tsc.getRunningTask() == ts) {
+                    tsc.cancelExecutingTask();
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * @param ts TaskStatus we are querying against.
+     * @return Whether or not the task represented by the status object is currently being run or
+     * is pending.
+     */
+    private boolean isCurrentlyActive(TaskStatus ts) {
+        synchronized (mActiveServices) {
+            for (TaskServiceContext serviceContext : mActiveServices) {
+                if (serviceContext.getRunningTask() == ts) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * A task is rescheduled with exponential back-off if the client requests this from their
+     * execution logic.
+     * A caveat is for idle-mode tasks, for which the idle-mode constraint will usurp the
+     * timeliness of the reschedule. For an idle-mode task, no deadline is given.
+     * @param failureToReschedule Provided task status that we will reschedule.
+     * @return A newly instantiated TaskStatus with the same constraints as the last task except
+     * with adjusted timing constraints.
+     */
+    private TaskStatus getRescheduleTaskForFailure(TaskStatus failureToReschedule) {
+        final long elapsedNowMillis = SystemClock.elapsedRealtime();
+        final Task task = failureToReschedule.getTask();
+
+        final long initialBackoffMillis = task.getInitialBackoffMillis();
+        final int backoffAttempt = failureToReschedule.getNumFailures() + 1;
+        long newEarliestRuntimeElapsed = elapsedNowMillis;
+
+        switch (task.getBackoffPolicy()) {
+            case Task.BackoffPolicy.LINEAR:
+                newEarliestRuntimeElapsed += initialBackoffMillis * backoffAttempt;
+                break;
+            default:
+                if (DEBUG) {
+                    Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
+                }
+            case Task.BackoffPolicy.EXPONENTIAL:
+                newEarliestRuntimeElapsed += Math.pow(initialBackoffMillis, backoffAttempt);
+                break;
+        }
+        long newLatestRuntimeElapsed = failureToReschedule.hasIdleConstraint() ? Long.MAX_VALUE
+                : newEarliestRuntimeElapsed + RESCHEDULE_WINDOW_SLOP_MILLIS;
+        return new TaskStatus(failureToReschedule, newEarliestRuntimeElapsed,
+                newLatestRuntimeElapsed, backoffAttempt);
+    }
+
+    /**
+     * Called after a periodic has executed so we can to re-add it. We take the last execution time
+     * of the task to be the time of completion (i.e. the time at which this function is called).
+     * This could be inaccurate b/c the task can run for as long as
+     * {@link com.android.server.task.TaskServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
+     * to underscheduling at least, rather than if we had taken the last execution time to be the
+     * start of the execution.
+     * @return A new task representing the execution criteria for this instantiation of the
+     * recurring task.
+     */
+    private TaskStatus getRescheduleTaskForPeriodic(TaskStatus periodicToReschedule) {
+        final long elapsedNow = SystemClock.elapsedRealtime();
+        // Compute how much of the period is remaining.
+        long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
+        long newEarliestRunTimeElapsed = elapsedNow + runEarly;
+        long period = periodicToReschedule.getTask().getIntervalMillis();
+        long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
+
+        if (DEBUG) {
+            Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
+                    newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
+        }
+        return new TaskStatus(periodicToReschedule, newEarliestRunTimeElapsed,
+                newLatestRuntimeElapsed, 0 /* backoffAttempt */);
+    }
+
+    // TaskCompletedListener implementations.
+
+    /**
+     * A task just finished executing. We fetch the
+     * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
+     * whether we want to reschedule we readd it to the controllers.
+     * @param taskStatus Completed task.
+     * @param needsReschedule Whether the implementing class should reschedule this task.
+     */
+    @Override
+    public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule) {
+        if (!stopTrackingTask(taskStatus)) {
+            if (DEBUG) {
+                Slog.e(TAG, "Error removing task: could not find task to remove. Was task" +
+                        "removed while executing?");
+            }
+            return;
+        }
+        if (needsReschedule) {
+            TaskStatus rescheduled = getRescheduleTaskForFailure(taskStatus);
+            startTrackingTask(rescheduled);
+        } else if (taskStatus.getTask().isPeriodic()) {
+            TaskStatus rescheduledPeriodic = getRescheduleTaskForPeriodic(taskStatus);
+            startTrackingTask(rescheduledPeriodic);
+        }
+        mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
     }
 
     // StateChangedListener implementations.
@@ -138,69 +394,236 @@
      * see which are ready. This will further decouple the controllers from the execution logic.
      */
     @Override
-    public void onTaskStateChanged(TaskStatus taskStatus) {
-        postCheckTasksMessage();
-
+    public void onControllerStateChanged() {
+        // Post a message to to run through the list of tasks and start/stop any that are eligible.
+        mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
     }
 
     @Override
     public void onTaskDeadlineExpired(TaskStatus taskStatus) {
-
+        mHandler.obtainMessage(MSG_TASK_EXPIRED, taskStatus);
     }
 
-    // TaskCompletedListener implementations.
+    private class TaskHandler extends Handler {
 
-    /**
-     * A task just finished executing. We fetch the
-     * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
-     * whether we want to reschedule we readd it to the controllers.
-     * @param serviceToken key for the service context in {@link #mActiveServices}.
-     * @param taskId Id of the task that is complete.
-     * @param needsReschedule Whether the implementing class should reschedule this task.
-     */
-    @Override
-    public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) {
-        final TaskServiceContext serviceContext = mActiveServices.get(serviceToken);
-        if (serviceContext == null) {
-            Log.e(TAG, "Task completed for invalid service context; " + serviceToken);
-            return;
+        public TaskHandler(Looper looper) {
+            super(looper);
         }
 
-    }
-
-    @Override
-    public void onAllTasksCompleted(int serviceToken) {
-        
-    }
-
-    private void assignTaskToServiceContext(TaskStatus ts) {
-        TaskServiceContext serviceContext =
-                mActiveServices.get(ts.getServiceToken());
-        if (serviceContext == null) {
-            serviceContext = new TaskServiceContext(this, mHandler.getLooper(), ts);
-            mActiveServices.put(ts.getServiceToken(), serviceContext);
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_TASK_EXPIRED:
+                    final TaskStatus expired = (TaskStatus) message.obj;  // Unused for now.
+                    queueReadyTasksForExecutionH();
+                    break;
+                case MSG_CHECK_TASKS:
+                    // Check the list of tasks and run some of them if we feel inclined.
+                    maybeQueueReadyTasksForExecutionH();
+                    break;
+            }
+            maybeRunNextPendingTaskH();
+            // Don't remove TASK_EXPIRED in case one came along while processing the queue.
+            removeMessages(MSG_CHECK_TASKS);
         }
-        serviceContext.addPendingTask(ts);
+
+        /**
+         * Run through list of tasks and execute all possible - at least one is expired so we do
+         * as many as we can.
+         */
+        private void queueReadyTasksForExecutionH() {
+            synchronized (mTasks) {
+                for (TaskStatus ts : mTasks.getTasks()) {
+                    final boolean criteriaSatisfied = ts.isReady();
+                    final boolean isRunning = isCurrentlyActive(ts);
+                    if (criteriaSatisfied && !isRunning) {
+                        synchronized (mPendingTasks) {
+                            mPendingTasks.add(ts);
+                        }
+                    } else if (!criteriaSatisfied && isRunning) {
+                        cancelTaskOnServiceContext(ts);
+                    }
+                }
+            }
+        }
+
+        /**
+         * The state of at least one task has changed. Here is where we could enforce various
+         * policies on when we want to execute tasks.
+         * Right now the policy is such:
+         *      If >1 of the ready tasks is idle mode we send all of them off
+         *      if more than 2 network connectivity tasks are ready we send them all off.
+         *      If more than 4 tasks total are ready we send them all off.
+         *      TODO: It would be nice to consolidate these sort of high-level policies somewhere.
+         */
+        private void maybeQueueReadyTasksForExecutionH() {
+            synchronized (mTasks) {
+                int idleCount = 0;
+                int connectivityCount = 0;
+                List<TaskStatus> runnableTasks = new ArrayList<TaskStatus>();
+                for (TaskStatus ts : mTasks.getTasks()) {
+                    final boolean criteriaSatisfied = ts.isReady();
+                    final boolean isRunning = isCurrentlyActive(ts);
+                    if (criteriaSatisfied && !isRunning) {
+                        if (ts.hasIdleConstraint()) {
+                            idleCount++;
+                        }
+                        if (ts.hasConnectivityConstraint() || ts.hasMeteredConstraint()) {
+                            connectivityCount++;
+                        }
+                        runnableTasks.add(ts);
+                    } else if (!criteriaSatisfied && isRunning) {
+                        cancelTaskOnServiceContext(ts);
+                    }
+                }
+                if (idleCount >= MIN_IDLE_COUNT || connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+                        runnableTasks.size() >= MIN_READY_TASKS_COUNT) {
+                    for (TaskStatus ts : runnableTasks) {
+                        synchronized (mPendingTasks) {
+                            mPendingTasks.add(ts);
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks the state of the pending queue against any available
+         * {@link com.android.server.task.TaskServiceContext} that can run a new task.
+         * {@link com.android.server.task.TaskServiceContext}.
+         */
+        private void maybeRunNextPendingTaskH() {
+            TaskStatus nextPending;
+            synchronized (mPendingTasks) {
+                nextPending = mPendingTasks.poll();
+            }
+            if (nextPending == null) {
+                return;
+            }
+
+            synchronized (mActiveServices) {
+                for (TaskServiceContext tsc : mActiveServices) {
+                    if (tsc.isAvailable()) {
+                        if (tsc.executeRunnableTask(nextPending)) {
+                            return;
+                        }
+                    }
+                }
+            }
+        }
     }
 
     /**
-     * @param ts TaskStatus we are querying against.
-     * @return Whether or not the task represented by the status object is currently being run or
-     * is pending.
+     * Binder stub trampoline implementation
      */
-    private boolean isCurrentlyActive(TaskStatus ts) {
-        TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken());
-        if (serviceContext == null) {
-            return false;
-        }
-        return serviceContext.hasTaskPending(ts);
-    }
+    final class TaskManagerStub extends ITaskManager.Stub {
+        /** Cache determination of whether a given app can persist tasks
+         * key is uid of the calling app; value is undetermined/true/false
+         */
+        private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
 
-    /**
-     * Post a message to {@link #mHandler} to run through the list of tasks and start/stop any that
-     * are eligible.
-     */
-    private void postCheckTasksMessage() {
-        mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
+        // Determine whether the caller is allowed to persist tasks, with a small cache
+        // because the lookup is expensive enough that we'd like to avoid repeating it.
+        // This must be called from within the calling app's binder identity!
+        private boolean canCallerPersistTasks() {
+            final boolean canPersist;
+            final int callingUid = Binder.getCallingUid();
+            synchronized (mPersistCache) {
+                Boolean cached = mPersistCache.get(callingUid);
+                if (cached) {
+                    canPersist = cached.booleanValue();
+                } else {
+                    // Persisting tasks is tantamount to running at boot, so we permit
+                    // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
+                    // permission
+                    int result = getContext().checkCallingPermission(
+                            android.Manifest.permission.RECEIVE_BOOT_COMPLETED);
+                    canPersist = (result == PackageManager.PERMISSION_GRANTED);
+                    mPersistCache.put(callingUid, canPersist);
+                }
+            }
+            return canPersist;
+        }
+
+        // ITaskManager implementation
+        @Override
+        public int schedule(Task task) throws RemoteException {
+            final boolean canPersist = canCallerPersistTasks();
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return TaskManagerService.this.schedule(task, uid, canPersist);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public List<Task> getAllPendingTasks() throws RemoteException {
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return TaskManagerService.this.getPendingTasks(uid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void cancelAll() throws RemoteException {
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                TaskManagerService.this.cancelTaskForUid(uid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void cancel(int taskId) throws RemoteException {
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                TaskManagerService.this.cancelTask(uid, taskId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * "dumpsys" infrastructure
+         */
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+            long identityToken = Binder.clearCallingIdentity();
+            try {
+                TaskManagerService.this.dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+    };
+
+    void dumpInternal(PrintWriter pw) {
+        synchronized (mTasks) {
+            pw.print("Registered tasks:");
+            if (mTasks.size() > 0) {
+                for (TaskStatus ts : mTasks.getTasks()) {
+                    pw.println();
+                    ts.dump(pw, "  ");
+                }
+            } else {
+                pw.println();
+                pw.println("No tasks scheduled.");
+            }
+        }
+        pw.println();
     }
 }
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
index b51cbb3..75e9212 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -36,20 +37,18 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.task.controllers.TaskStatus;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * Maintains information required to bind to a {@link android.app.task.TaskService}. This binding
- * is reused to start concurrent tasks on the TaskService. Information here is unique
- * to the service.
- * Functionality provided by this class:
- *     - Managages wakelock for the service.
- *     - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
- *     -
+ * Handles client binding and lifecycle of a task. A task will only execute one at a time on an
+ * instance of this class.
  */
 public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+    private static final boolean DEBUG = true;
     private static final String TAG = "TaskServiceContext";
     /** Define the maximum # of tasks allowed to run on a service at once. */
     private static final int defaultMaxActiveTasksPerService =
@@ -66,10 +65,10 @@
     };
 
     // States that a task occupies while interacting with the client.
-    private static final int VERB_STARTING = 0;
-    private static final int VERB_EXECUTING = 1;
-    private static final int VERB_STOPPING = 2;
-    private static final int VERB_PENDING = 3;
+    static final int VERB_BINDING = 0;
+    static final int VERB_STARTING = 1;
+    static final int VERB_EXECUTING = 2;
+    static final int VERB_STOPPING = 3;
 
     // Messages that result from interactions with the client service.
     /** System timed out waiting for a response. */
@@ -77,178 +76,173 @@
     /** Received a callback from client. */
     private static final int MSG_CALLBACK = 1;
     /** Run through list and start any ready tasks.*/
-    private static final int MSG_CHECK_PENDING = 2;
-    /** Cancel an active task. */
+    private static final int MSG_SERVICE_BOUND = 2;
+    /** Cancel a task. */
     private static final int MSG_CANCEL = 3;
-    /** Add a pending task. */
-    private static final int MSG_ADD_PENDING = 4;
-    /** Client crashed, so we need to wind things down. */
-    private static final int MSG_SHUTDOWN = 5;
+    /** Shutdown the Task. Used when the client crashes and we can't die gracefully.*/
+    private static final int MSG_SHUTDOWN_EXECUTION = 4;
 
-    /** Used to identify this task service context when communicating with the TaskManager. */
-    final int token;
-    final ComponentName component;
-    final int userId;
-    ITaskService service;
     private final Handler mCallbackHandler;
-    /** Tasks that haven't been sent to the client for execution yet. */
-    private final SparseArray<ActiveTask> mPending;
+    /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
+    private final TaskCompletedListener mCompletedListener;
     /** Used for service binding, etc. */
     private final Context mContext;
-    /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
-    final private TaskCompletedListener mCompletedListener;
-    private final PowerManager.WakeLock mWakeLock;
+    private PowerManager.WakeLock mWakeLock;
 
-    /** Whether this service is actively bound. */
-    boolean mBound;
+    // Execution state.
+    private TaskParams mParams;
+    @VisibleForTesting
+    int mVerb;
+    private AtomicBoolean mCancelled = new AtomicBoolean();
 
-    TaskServiceContext(TaskManagerService taskManager, Looper looper, TaskStatus taskStatus) {
-        mContext = taskManager.getContext();
-        this.component = taskStatus.getServiceComponent();
-        this.token = taskStatus.getServiceToken();
-        this.userId = taskStatus.getUserId();
+    /** All the information maintained about the task currently being executed. */
+    private TaskStatus mRunningTask;
+    /** Binder to the client service. */
+    ITaskService service;
+
+    private final Object mAvailableLock = new Object();
+    /** Whether this context is free. */
+    @GuardedBy("mAvailableLock")
+    private boolean mAvailable;
+
+    TaskServiceContext(TaskManagerService service, Looper looper) {
+        this(service.getContext(), service, looper);
+    }
+
+    @VisibleForTesting
+    TaskServiceContext(Context context, TaskCompletedListener completedListener, Looper looper) {
+        mContext = context;
         mCallbackHandler = new TaskServiceHandler(looper);
-        mPending = new SparseArray<ActiveTask>();
-        mCompletedListener = taskManager;
-        final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mCompletedListener = completedListener;
+    }
+
+    /**
+     * Give a task to this context for execution. Callers must first check {@link #isAvailable()}
+     * to make sure this is a valid context.
+     * @param ts The status of the task that we are going to run.
+     * @return True if the task was accepted and is going to run.
+     */
+    boolean executeRunnableTask(TaskStatus ts) {
+        synchronized (mAvailableLock) {
+            if (!mAvailable) {
+                Slog.e(TAG, "Starting new runnable but context is unavailable > Error.");
+                return false;
+            }
+            mAvailable = false;
+        }
+
+        final PowerManager pm =
+                (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                TM_WAKELOCK_PREFIX + component.getPackageName());
-        mWakeLock.setWorkSource(new WorkSource(taskStatus.getUid()));
+                TM_WAKELOCK_PREFIX + ts.getServiceComponent().getPackageName());
+        mWakeLock.setWorkSource(new WorkSource(ts.getUid()));
         mWakeLock.setReferenceCounted(false);
+
+        mRunningTask = ts;
+        mParams = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
+
+        mVerb = VERB_BINDING;
+        final Intent intent = new Intent().setComponent(ts.getServiceComponent());
+        boolean binding = mContext.bindServiceAsUser(intent, this,
+                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+                new UserHandle(ts.getUserId()));
+        if (!binding) {
+            if (DEBUG) {
+                Slog.d(TAG, ts.getServiceComponent().getShortClassName() + " unavailable.");
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /** Used externally to query the running task. Will return null if there is no task running. */
+    TaskStatus getRunningTask() {
+        return mRunningTask;
+    }
+
+    /** Called externally when a task that was scheduled for execution should be cancelled. */
+    void cancelExecutingTask() {
+        mCallbackHandler.obtainMessage(MSG_CANCEL).sendToTarget();
+    }
+
+    /**
+     * @return Whether this context is available to handle incoming work.
+     */
+    boolean isAvailable() {
+        synchronized (mAvailableLock) {
+            return mAvailable;
+        }
     }
 
     @Override
     public void taskFinished(int taskId, boolean reschedule) {
+        if (!verifyCallingUid()) {
+            return;
+        }
         mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
                 .sendToTarget();
     }
 
     @Override
     public void acknowledgeStopMessage(int taskId, boolean reschedule) {
+        if (!verifyCallingUid()) {
+            return;
+        }
         mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
                 .sendToTarget();
     }
 
     @Override
     public void acknowledgeStartMessage(int taskId, boolean ongoing) {
+        if (!verifyCallingUid()) {
+            return;
+        }
         mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, ongoing ? 1 : 0).sendToTarget();
     }
 
     /**
-     * Queue up this task to run on the client. This will execute the task as quickly as possible.
-     * @param ts Status of the task to run.
-     */
-    public void addPendingTask(TaskStatus ts) {
-        final TaskParams params = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
-        final ActiveTask newTask = new ActiveTask(params, VERB_PENDING);
-        mCallbackHandler.obtainMessage(MSG_ADD_PENDING, newTask).sendToTarget();
-        if (!mBound) {
-            Intent intent = new Intent().setComponent(component);
-            boolean binding = mContext.bindServiceAsUser(intent, this,
-                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
-                    new UserHandle(userId));
-            if (!binding) {
-                Log.e(TAG, component.getShortClassName() + " unavailable.");
-                cancelPendingTask(ts);
-            }
-        }
-    }
-
-    /**
-     * Called externally when a task that was scheduled for execution should be cancelled.
-     * @param ts The status of the task to cancel.
-     */
-    public void cancelPendingTask(TaskStatus ts) {
-        mCallbackHandler.obtainMessage(MSG_CANCEL, ts.getTaskId(), -1 /* arg2 */)
-                .sendToTarget();
-    }
-
-    /**
-     * MSG_TIMEOUT is sent with the {@link com.android.server.task.TaskServiceContext.ActiveTask}
-     * set in the {@link Message#obj} field. This makes it easier to remove timeouts for a given
-     * ActiveTask.
-     * @param op Operation that is taking place.
-     */
-    private void scheduleOpTimeOut(ActiveTask op) {
-        mCallbackHandler.removeMessages(MSG_TIMEOUT, op);
-
-        final long timeoutMillis = (op.verb == VERB_EXECUTING) ?
-                EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
-        if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
-            Slog.d(TAG, "Scheduling time out for '" + component.getShortClassName() + "' tId: " +
-                    op.params.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
-        }
-        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, op);
-        mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
-    }
-
-    /**
-     * @return true if this task is pending or active within this context.
-     */
-    public boolean hasTaskPending(TaskStatus taskStatus) {
-        synchronized (mPending) {
-            return mPending.get(taskStatus.getTaskId()) != null;
-        }
-    }
-
-    public boolean isBound() {
-        return mBound;
-    }
-
-    /**
-     * We acquire/release the wakelock on onServiceConnected/unbindService. This mirrors the work
+     * We acquire/release a wakelock on onServiceConnected/unbindService. This mirrors the work
      * we intend to send to the client - we stop sending work when the service is unbound so until
      * then we keep the wakelock.
-     * @param name The concrete component name of the service that has
-     * been connected.
+     * @param name The concrete component name of the service that has been connected.
      * @param service The IBinder of the Service's communication channel,
      */
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
-        mBound = true;
+        if (!name.equals(mRunningTask.getServiceComponent())) {
+            mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
+            return;
+        }
         this.service = ITaskService.Stub.asInterface(service);
-        // Remove all timeouts. We've just connected to the client so there are no other
-        // MSG_TIMEOUTs at this point.
+        // Remove all timeouts.
         mCallbackHandler.removeMessages(MSG_TIMEOUT);
         mWakeLock.acquire();
-        mCallbackHandler.obtainMessage(MSG_CHECK_PENDING).sendToTarget();
+        mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
     }
 
     /**
-     * When the client service crashes we can have a couple tasks executing, in various stages of
-     * undress. We'll cancel all of them and request that they be rescheduled.
+     * If the client service crashes we reschedule this task and clean up.
      * @param name The concrete component name of the service whose
      */
     @Override
     public void onServiceDisconnected(ComponentName name) {
-        // Service disconnected... probably client crashed.
-        startShutdown();
+        mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
     }
 
     /**
-     * We don't just shutdown outright - we make sure the scheduler isn't going to send us any more
-     * tasks, then we do the shutdown.
+     * This class is reused across different clients, and passes itself in as a callback. Check
+     * whether the client exercising the callback is the client we expect.
+     * @return True if the binder calling is coming from the client we expect.
      */
-    private void startShutdown() {
-        mCompletedListener.onAllTasksCompleted(token);
-        mCallbackHandler.obtainMessage(MSG_SHUTDOWN).sendToTarget();
-    }
-
-    /** Tracks a task across its various state changes. */
-    private static class ActiveTask {
-        final TaskParams params;
-        int verb;
-        AtomicBoolean cancelled = new AtomicBoolean();
-
-        ActiveTask(TaskParams params, int verb) {
-            this.params = params;
-            this.verb = verb;
+    private boolean verifyCallingUid() {
+        if (mRunningTask == null || Binder.getCallingUid() != mRunningTask.getUid()) {
+            if (DEBUG) {
+                Slog.d(TAG, "Stale callback received, ignoring.");
+            }
+            return false;
         }
-
-        @Override
-        public String toString() {
-            return params.getTaskId() + " " + VERB_STRINGS[verb];
-        }
+        return true;
     }
 
     /**
@@ -264,52 +258,67 @@
         @Override
         public void handleMessage(Message message) {
             switch (message.what) {
-                case MSG_ADD_PENDING:
-                    if (message.obj != null) {
-                        ActiveTask pendingTask = (ActiveTask) message.obj;
-                        mPending.put(pendingTask.params.getTaskId(), pendingTask);
-                    }
-                    // fall through.
-                case MSG_CHECK_PENDING:
-                    checkPendingTasksH();
+                case MSG_SERVICE_BOUND:
+                    handleServiceBoundH();
                     break;
                 case MSG_CALLBACK:
-                    ActiveTask receivedCallback = mPending.get(message.arg1);
-                    removeMessages(MSG_TIMEOUT, receivedCallback);
-
-                    if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
-                        Log.d(TAG, "MSG_CALLBACK of : " + receivedCallback);
+                    if (DEBUG) {
+                        Slog.d(TAG, "MSG_CALLBACK of : " + mRunningTask);
                     }
+                    removeMessages(MSG_TIMEOUT);
 
-                    if (receivedCallback.verb == VERB_STARTING) {
+                    if (mVerb == VERB_STARTING) {
                         final boolean workOngoing = message.arg2 == 1;
-                        handleStartedH(receivedCallback, workOngoing);
-                    } else if (receivedCallback.verb == VERB_EXECUTING ||
-                            receivedCallback.verb == VERB_STOPPING) {
+                        handleStartedH(workOngoing);
+                    } else if (mVerb == VERB_EXECUTING ||
+                            mVerb == VERB_STOPPING) {
                         final boolean reschedule = message.arg2 == 1;
-                        handleFinishedH(receivedCallback, reschedule);
+                        handleFinishedH(reschedule);
                     } else {
-                        if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
-                            Log.d(TAG, "Unrecognised callback: " + receivedCallback);
+                        if (DEBUG) {
+                            Slog.d(TAG, "Unrecognised callback: " + mRunningTask);
                         }
                     }
                     break;
                 case MSG_CANCEL:
-                    ActiveTask cancelled = mPending.get(message.arg1);
-                    handleCancelH(cancelled);
+                    handleCancelH();
                     break;
                 case MSG_TIMEOUT:
-                    // Timeout msgs have the ActiveTask ref so we can remove them easily.
-                    handleOpTimeoutH((ActiveTask) message.obj);
+                    handleOpTimeoutH();
                     break;
-                case MSG_SHUTDOWN:
-                    handleShutdownH();
-                    break;
+                case MSG_SHUTDOWN_EXECUTION:
+                    closeAndCleanupTaskH(true /* needsReschedule */);
                 default:
                     Log.e(TAG, "Unrecognised message: " + message);
             }
         }
 
+        /** Start the task on the service. */
+        private void handleServiceBoundH() {
+            if (mVerb != VERB_BINDING) {
+                Slog.e(TAG, "Sending onStartTask for a task that isn't pending. "
+                        + VERB_STRINGS[mVerb]);
+                closeAndCleanupTaskH(false /* reschedule */);
+                return;
+            }
+            if (mCancelled.get()) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Task cancelled while waiting for bind to complete. "
+                            + mRunningTask);
+                }
+                closeAndCleanupTaskH(true /* reschedule */);
+                return;
+            }
+            try {
+                mVerb = VERB_STARTING;
+                scheduleOpTimeOut();
+                service.startTask(mParams);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sending onStart message to '" +
+                        mRunningTask.getServiceComponent().getShortClassName() + "' ", e);
+            }
+        }
+
         /**
          * State behaviours.
          * VERB_STARTING   -> Successful start, change task to VERB_EXECUTING and post timeout.
@@ -317,24 +326,25 @@
          *     _EXECUTING  -> Error
          *     _STOPPING   -> Error
          */
-        private void handleStartedH(ActiveTask started, boolean workOngoing) {
-            switch (started.verb) {
+        private void handleStartedH(boolean workOngoing) {
+            switch (mVerb) {
                 case VERB_STARTING:
-                    started.verb = VERB_EXECUTING;
+                    mVerb = VERB_EXECUTING;
                     if (!workOngoing) {
                         // Task is finished already so fast-forward to handleFinished.
-                        handleFinishedH(started, false);
+                        handleFinishedH(false);
                         return;
-                    } else if (started.cancelled.get()) {
-                        // Cancelled *while* waiting for acknowledgeStartMessage from client.
-                        handleCancelH(started);
-                        return;
-                    } else {
-                        scheduleOpTimeOut(started);
                     }
+                    if (mCancelled.get()) {
+                        // Cancelled *while* waiting for acknowledgeStartMessage from client.
+                        handleCancelH();
+                        return;
+                    }
+                    scheduleOpTimeOut();
                     break;
                 default:
-                    Log.e(TAG, "Handling started task but task wasn't starting! " + started);
+                    Log.e(TAG, "Handling started task but task wasn't starting! Was "
+                            + VERB_STRINGS[mVerb] + ".");
                     return;
             }
         }
@@ -345,155 +355,104 @@
          *     _STARTING   -> Error
          *     _PENDING    -> Error
          */
-        private void handleFinishedH(ActiveTask executedTask, boolean reschedule) {
-            switch (executedTask.verb) {
+        private void handleFinishedH(boolean reschedule) {
+            switch (mVerb) {
                 case VERB_EXECUTING:
                 case VERB_STOPPING:
-                    closeAndCleanupTaskH(executedTask, reschedule);
+                    closeAndCleanupTaskH(reschedule);
                     break;
                 default:
-                    Log.e(TAG, "Got an execution complete message for a task that wasn't being" +
-                            "executed. " + executedTask);
+                    Slog.e(TAG, "Got an execution complete message for a task that wasn't being" +
+                            "executed. Was " + VERB_STRINGS[mVerb] + ".");
             }
         }
 
         /**
          * A task can be in various states when a cancel request comes in:
-         * VERB_PENDING    -> Remove from queue.
-         *     _STARTING   -> Mark as cancelled and wait for {@link #acknowledgeStartMessage(int)}.
+         * VERB_BINDING    -> Cancelled before bind completed. Mark as cancelled and wait for
+         *                    {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
+         *     _STARTING   -> Mark as cancelled and wait for
+         *                    {@link TaskServiceContext#acknowledgeStartMessage(int, boolean)}
          *     _EXECUTING  -> call {@link #sendStopMessageH}}.
          *     _ENDING     -> No point in doing anything here, so we ignore.
          */
-        private void handleCancelH(ActiveTask cancelledTask) {
-            switch (cancelledTask.verb) {
-                case VERB_PENDING:
-                    mPending.remove(cancelledTask.params.getTaskId());
-                    break;
+        private void handleCancelH() {
+            switch (mVerb) {
+                case VERB_BINDING:
                 case VERB_STARTING:
-                    cancelledTask.cancelled.set(true);
+                    mCancelled.set(true);
                     break;
                 case VERB_EXECUTING:
-                    cancelledTask.verb = VERB_STOPPING;
-                    sendStopMessageH(cancelledTask);
+                    sendStopMessageH();
                     break;
                 case VERB_STOPPING:
                     // Nada.
                     break;
                 default:
-                    Log.e(TAG, "Cancelling a task without a valid verb: " + cancelledTask);
+                    Slog.e(TAG, "Cancelling a task without a valid verb: " + mVerb);
                     break;
             }
         }
 
-        /**
-         * This TaskServiceContext is shutting down. Remove all the tasks from the pending queue
-         * and reschedule them as if they had failed.
-         * Before posting this message, caller must invoke
-         * {@link com.android.server.task.TaskCompletedListener#onAllTasksCompleted(int)}.
-         */
-        private void handleShutdownH() {
-            for (int i = 0; i < mPending.size(); i++) {
-                ActiveTask at = mPending.valueAt(i);
-                closeAndCleanupTaskH(at, true /* needsReschedule */);
-            }
-            mWakeLock.release();
-            mContext.unbindService(TaskServiceContext.this);
-            service = null;
-            mBound = false;
-        }
-
-        /**
-         * MSG_TIMEOUT gets processed here.
-         * @param timedOutTask The task that timed out.
-         */
-        private void handleOpTimeoutH(ActiveTask timedOutTask) {
+        /** Process MSG_TIMEOUT here. */
+        private void handleOpTimeoutH() {
             if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
-                Log.d(TAG, "MSG_TIMEOUT of " + component.getShortClassName() + " : "
-                        + timedOutTask.params.getTaskId());
+                Log.d(TAG, "MSG_TIMEOUT of " +
+                        mRunningTask.getServiceComponent().getShortClassName() + " : "
+                        + mParams.getTaskId());
             }
 
-            final int taskId = timedOutTask.params.getTaskId();
-            switch (timedOutTask.verb) {
+            final int taskId = mParams.getTaskId();
+            switch (mVerb) {
                 case VERB_STARTING:
                     // Client unresponsive - wedged or failed to respond in time. We don't really
                     // know what happened so let's log it and notify the TaskManager
                     // FINISHED/NO-RETRY.
                     Log.e(TAG, "No response from client for onStartTask '" +
-                            component.getShortClassName() + "' tId: " + taskId);
-                    closeAndCleanupTaskH(timedOutTask, false /* needsReschedule */);
+                            mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
+                            + taskId);
+                    closeAndCleanupTaskH(false /* needsReschedule */);
                     break;
                 case VERB_STOPPING:
                     // At least we got somewhere, so fail but ask the TaskManager to reschedule.
                     Log.e(TAG, "No response from client for onStopTask, '" +
-                            component.getShortClassName() + "' tId: " + taskId);
-                    closeAndCleanupTaskH(timedOutTask, true /* needsReschedule */);
+                            mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
+                            + taskId);
+                    closeAndCleanupTaskH(true /* needsReschedule */);
                     break;
                 case VERB_EXECUTING:
                     // Not an error - client ran out of time.
                     Log.i(TAG, "Client timed out while executing (no taskFinished received)." +
                             " Reporting failure and asking for reschedule. "  +
-                            component.getShortClassName() + "' tId: " + taskId);
-                    sendStopMessageH(timedOutTask);
+                            mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
+                            + taskId);
+                    sendStopMessageH();
                     break;
                 default:
                     Log.e(TAG, "Handling timeout for an unknown active task state: "
-                            + timedOutTask);
+                            + mRunningTask);
                     return;
             }
         }
 
         /**
-         * Called on the handler thread. Checks the state of the pending queue and starts the task
-         * if it can. The task only starts if there is capacity on the service.
+         * Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
+         * VERB_STOPPING.
          */
-        private void checkPendingTasksH() {
-            if (!mBound) {
-                return;
-            }
-            for (int i = 0; i < mPending.size() && i < defaultMaxActiveTasksPerService; i++) {
-                ActiveTask at = mPending.valueAt(i);
-                if (at.verb != VERB_PENDING) {
-                    continue;
-                }
-                sendStartMessageH(at);
-            }
-        }
-
-        /**
-         * Already running, need to stop. Rund on handler.
-         * @param stoppingTask Task we are sending onStopMessage for. This task will be moved from
-         *                     VERB_EXECUTING -> VERB_STOPPING.
-         */
-        private void sendStopMessageH(ActiveTask stoppingTask) {
-            mCallbackHandler.removeMessages(MSG_TIMEOUT, stoppingTask);
-            if (stoppingTask.verb != VERB_EXECUTING) {
-                Log.e(TAG, "Sending onStopTask for a task that isn't started. " + stoppingTask);
-                // TODO: Handle error?
+        private void sendStopMessageH() {
+            mCallbackHandler.removeMessages(MSG_TIMEOUT);
+            if (mVerb != VERB_EXECUTING) {
+                Log.e(TAG, "Sending onStopTask for a task that isn't started. " + mRunningTask);
+                closeAndCleanupTaskH(false /* reschedule */);
                 return;
             }
             try {
-                service.stopTask(stoppingTask.params);
-                stoppingTask.verb = VERB_STOPPING;
-                scheduleOpTimeOut(stoppingTask);
+                mVerb = VERB_STOPPING;
+                scheduleOpTimeOut();
+                service.stopTask(mParams);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error sending onStopTask to client.", e);
-                closeAndCleanupTaskH(stoppingTask, false);
-            }
-        }
-
-        /** Start the task on the service. */
-        private void sendStartMessageH(ActiveTask pendingTask) {
-            if (pendingTask.verb != VERB_PENDING) {
-                Log.e(TAG, "Sending onStartTask for a task that isn't pending. " + pendingTask);
-                // TODO: Handle error?
-            }
-            try {
-                service.startTask(pendingTask.params);
-                pendingTask.verb = VERB_STARTING;
-                scheduleOpTimeOut(pendingTask);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error sending onStart message to '" + component.getShortClassName()
-                        + "' ", e);
+                closeAndCleanupTaskH(false);
             }
         }
 
@@ -503,13 +462,42 @@
          * or from acknowledging the stop message we sent. Either way, we're done tracking it and
          * we want to clean up internally.
          */
-        private void closeAndCleanupTaskH(ActiveTask completedTask, boolean reschedule) {
-            removeMessages(MSG_TIMEOUT, completedTask);
-            mPending.remove(completedTask.params.getTaskId());
-            if (mPending.size() == 0) {
-                startShutdown();
+        private void closeAndCleanupTaskH(boolean reschedule) {
+            removeMessages(MSG_TIMEOUT);
+            mWakeLock.release();
+            mContext.unbindService(TaskServiceContext.this);
+            mWakeLock = null;
+
+            mRunningTask = null;
+            mParams = null;
+            mVerb = -1;
+            mCancelled.set(false);
+
+            service = null;
+
+            mCompletedListener.onTaskCompleted(mRunningTask, reschedule);
+            synchronized (mAvailableLock) {
+                mAvailable = true;
             }
-            mCompletedListener.onTaskCompleted(token, completedTask.params.getTaskId(), reschedule);
+        }
+
+        /**
+         * Called when sending a message to the client, over whose execution we have no control. If we
+         * haven't received a response in a certain amount of time, we want to give up and carry on
+         * with life.
+         */
+        private void scheduleOpTimeOut() {
+            mCallbackHandler.removeMessages(MSG_TIMEOUT);
+
+            final long timeoutMillis = (mVerb == VERB_EXECUTING) ?
+                    EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
+            if (DEBUG) {
+                Slog.d(TAG, "Scheduling time out for '" +
+                        mRunningTask.getServiceComponent().getShortClassName() + "' tId: " +
+                        mParams.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
+            }
+            Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
+            mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
         }
     }
 }
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
index 3bfc8a5..f72ab22 100644
--- a/services/core/java/com/android/server/task/TaskStore.java
+++ b/services/core/java/com/android/server/task/TaskStore.java
@@ -16,12 +16,18 @@
 
 package com.android.server.task;
 
+import android.app.task.Task;
 import android.content.Context;
-import android.content.Task;
+import android.util.ArraySet;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.server.task.controllers.TaskStatus;
 
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
 /**
  * Maintain a list of classes, and accessor methods/logic for these tasks.
  * This class offers the following functionality:
@@ -35,53 +41,122 @@
  *       - This class is <strong>not</strong> thread-safe.
  */
 public class TaskStore {
-
-    /**
-     * Master list, indexed by {@link com.android.server.task.controllers.TaskStatus#hashCode()}.
-     */
-    final SparseArray<TaskStatus> mTasks;
+    private static final String TAG = "TaskManagerStore";
+    /** Threshold to adjust how often we want to write to the db. */
+    private static final int MAX_OPS_BEFORE_WRITE = 1;
+    final ArraySet<TaskStatus> mTasks;
     final Context mContext;
 
+    private int mDirtyOperations;
+
     TaskStore(Context context) {
-        mTasks = intialiseTaskMapFromDisk();
+        mTasks = intialiseTasksFromDisk();
         mContext = context;
+        mDirtyOperations = 0;
     }
 
     /**
-     * Add a task to the master list, persisting it if necessary.
-     * Will first check to see if the task already exists. If so, it will replace it.
-     * {@link android.content.pm.PackageManager} is queried to see if the calling package has
-     * permission to
-     * @param task Task to add.
-     * @return The initialised TaskStatus object if this operation was successful, null if it
-     * failed.
+     * Add a task to the master list, persisting it if necessary. If the TaskStatus already exists,
+     * it will be replaced.
+     * @param taskStatus Task to add.
+     * @return true if the operation succeeded.
      */
-    public TaskStatus addNewTaskForUser(Task task, int userId, int uId,
-                                                     boolean canPersistTask) {
-        TaskStatus taskStatus = TaskStatus.getForTaskAndUser(task, userId, uId);
-        if (canPersistTask && task.isPeriodic()) {
-            if (writeStatusToDisk()) {
-                mTasks.put(taskStatus.hashCode(), taskStatus);
+    public boolean add(TaskStatus taskStatus) {
+        if (taskStatus.isPersisted()) {
+            if (!maybeWriteStatusToDisk()) {
+                return false;
             }
         }
-        return taskStatus;
+        mTasks.remove(taskStatus);
+        mTasks.add(taskStatus);
+        return true;
+    }
+
+    public int size() {
+        return mTasks.size();
     }
 
     /**
-     * Remove the provided task. Will also delete the task if it was persisted. Note that this
-     * function does not return the validity of the operation, as we assume a delete will always
-     * succeed.
-     * @param task Task to remove.
+     * Remove the provided task. Will also delete the task if it was persisted.
+     * @return The TaskStatus that was removed, or null if an invalid token was provided.
      */
-    public void remove(Task task) {
+    public boolean remove(TaskStatus taskStatus) {
+        boolean removed = mTasks.remove(taskStatus);
+        if (!removed) {
+            Slog.e(TAG, "Error removing task: " + taskStatus);
+            return false;
+        } else {
+            maybeWriteStatusToDisk();
+        }
+        return true;
+    }
 
+    /**
+     * Removes all TaskStatus objects for a given uid from the master list. Note that it is
+     * possible to remove a task that is pending/active. This operation will succeed, and the
+     * removal will take effect when the task has completed executing.
+     * @param uid Uid of the requesting app.
+     * @return True if at least one task was removed, false if nothing matching the provided uId
+     * was found.
+     */
+    public boolean removeAllByUid(int uid) {
+        Iterator<TaskStatus> it = mTasks.iterator();
+        boolean removed = false;
+        while (it.hasNext()) {
+            TaskStatus ts = it.next();
+            if (ts.getUid() == uid) {
+                it.remove();
+                removed = true;
+            }
+        }
+        if (removed) {
+            maybeWriteStatusToDisk();
+        }
+        return removed;
+    }
+
+    /**
+     * Remove the TaskStatus that matches the provided uId and taskId.  Note that it is possible
+     * to remove a task that is pending/active. This operation will succeed, and the removal will
+     * take effect when the task has completed executing.
+     * @param uid Uid of the requesting app.
+     * @param taskId Task id, specified at schedule-time.
+     * @return true if a removal occurred, false if the provided parameters didn't match anything.
+     */
+    public boolean remove(int uid, int taskId) {
+        Iterator<TaskStatus> it = mTasks.iterator();
+        while (it.hasNext()) {
+            TaskStatus ts = it.next();
+            if (ts.getUid() == uid && ts.getTaskId() == taskId) {
+                it.remove();
+                maybeWriteStatusToDisk();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return The live array of TaskStatus objects.
+     */
+    public Set<TaskStatus> getTasks() {
+        return mTasks;
     }
 
     /**
      * Every time the state changes we write all the tasks in one swathe, instead of trying to
      * track incremental changes.
+     * @return Whether the operation was successful. This will only fail for e.g. if the system is
+     * low on storage. If this happens, we continue as normal
      */
-    private boolean writeStatusToDisk() {
+    private boolean maybeWriteStatusToDisk() {
+        mDirtyOperations++;
+        if (mDirtyOperations > MAX_OPS_BEFORE_WRITE) {
+            for (TaskStatus ts : mTasks) {
+                //
+            }
+            mDirtyOperations = 0;
+        }
         return true;
     }
 
@@ -90,14 +165,7 @@
      * @return
      */
     // TODO: Implement this.
-    private SparseArray<TaskStatus> intialiseTaskMapFromDisk() {
-        return new SparseArray<TaskStatus>();
-    }
-
-    /**
-     * @return The live array of TaskStatus objects.
-     */
-    public SparseArray<TaskStatus> getTasks() {
-        return mTasks;
+    private ArraySet<TaskStatus> intialiseTasksFromDisk() {
+        return new ArraySet<TaskStatus>();
     }
 }
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
index 6a4e1f3..474af8f 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -25,6 +25,7 @@
 import android.net.NetworkInfo;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.Slog;
 
 import com.android.server.task.TaskManagerService;
 
@@ -32,21 +33,33 @@
 import java.util.List;
 
 /**
- *
+ * Handles changes in connectivity.
+ * We are only interested in metered vs. unmetered networks, and we're interested in them on a
+ * per-user basis.
  */
 public class ConnectivityController extends StateController {
     private static final String TAG = "TaskManager.Connectivity";
+    private static final boolean DEBUG = true;
 
     private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
     private final BroadcastReceiver mConnectivityChangedReceiver =
             new ConnectivityChangedReceiver();
+    /** Singleton. */
+    private static ConnectivityController mSingleton;
 
     /** Track whether the latest active network is metered. */
     private boolean mMetered;
     /** Track whether the latest active network is connected. */
     private boolean mConnectivity;
 
-    public ConnectivityController(TaskManagerService service) {
+    public static synchronized ConnectivityController get(TaskManagerService taskManager) {
+        if (mSingleton == null) {
+            mSingleton = new ConnectivityController(taskManager);
+        }
+        return mSingleton;
+    }
+
+    private ConnectivityController(TaskManagerService service) {
         super(service);
         // Register connectivity changed BR.
         IntentFilter intentFilter = new IntentFilter();
@@ -56,7 +69,7 @@
     }
 
     @Override
-    public void maybeTrackTaskState(TaskStatus taskStatus) {
+    public synchronized void maybeStartTrackingTask(TaskStatus taskStatus) {
         if (taskStatus.hasConnectivityConstraint() || taskStatus.hasMeteredConstraint()) {
             taskStatus.connectivityConstraintSatisfied.set(mConnectivity);
             taskStatus.meteredConstraintSatisfied.set(mMetered);
@@ -65,7 +78,7 @@
     }
 
     @Override
-    public void removeTaskStateIfTracked(TaskStatus taskStatus) {
+    public synchronized void maybeStopTrackingTask(TaskStatus taskStatus) {
         mTrackedTasks.remove(taskStatus);
     }
 
@@ -73,16 +86,20 @@
      * @param userId Id of the user for whom we are updating the connectivity state.
      */
     private void updateTrackedTasks(int userId) {
+        boolean changed = false;
         for (TaskStatus ts : mTrackedTasks) {
-            if (ts.userId != userId) {
+            if (ts.getUserId() != userId) {
                 continue;
             }
             boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
             boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
             if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
-                    mStateChangedListener.onTaskStateChanged(ts);
+                    changed = true;
             }
         }
+        if (changed) {
+            mStateChangedListener.onControllerStateChanged();
+        }
     }
 
     class ConnectivityChangedReceiver extends BroadcastReceiver {
@@ -106,7 +123,7 @@
                         context.getSystemService(Context.CONNECTIVITY_SERVICE);
                 final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
                 // This broadcast gets sent a lot, only update if the active network has changed.
-                if (activeNetwork.getType() == networkType) {
+                if (activeNetwork != null && activeNetwork.getType() == networkType) {
                     final int userid = context.getUserId();
                     mMetered = false;
                     mConnectivity =
@@ -117,7 +134,9 @@
                     updateTrackedTasks(userid);
                 }
             } else {
-                Log.w(TAG, "Unrecognised action in intent: " + action);
+                if (DEBUG) {
+                    Slog.d(TAG, "Unrecognised action in intent: " + action);
+                }
             }
         }
     };
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/task/controllers/IdleController.java
index a319a31..9489644 100644
--- a/services/core/java/com/android/server/task/controllers/IdleController.java
+++ b/services/core/java/com/android/server/task/controllers/IdleController.java
@@ -49,7 +49,7 @@
     private static Object sCreationLock = new Object();
     private static volatile IdleController sController;
 
-    public IdleController getController(TaskManagerService service) {
+    public static IdleController get(TaskManagerService service) {
         synchronized (sCreationLock) {
             if (sController == null) {
                 sController = new IdleController(service);
@@ -67,7 +67,7 @@
      * StateController interface
      */
     @Override
-    public void maybeTrackTaskState(TaskStatus taskStatus) {
+    public void maybeStartTrackingTask(TaskStatus taskStatus) {
         if (taskStatus.hasIdleConstraint()) {
             synchronized (mTrackedTasks) {
                 mTrackedTasks.add(taskStatus);
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public void removeTaskStateIfTracked(TaskStatus taskStatus) {
+    public void maybeStopTrackingTask(TaskStatus taskStatus) {
         synchronized (mTrackedTasks) {
             mTrackedTasks.remove(taskStatus);
         }
@@ -90,9 +90,9 @@
         synchronized (mTrackedTasks) {
             for (TaskStatus task : mTrackedTasks) {
                 task.idleConstraintSatisfied.set(isIdle);
-                mStateChangedListener.onTaskStateChanged(task);
             }
         }
+        mStateChangedListener.onControllerStateChanged();
     }
 
     /**
diff --git a/services/core/java/com/android/server/task/controllers/StateController.java b/services/core/java/com/android/server/task/controllers/StateController.java
index e1cd662..ed31eac 100644
--- a/services/core/java/com/android/server/task/controllers/StateController.java
+++ b/services/core/java/com/android/server/task/controllers/StateController.java
@@ -42,10 +42,10 @@
      * Also called when updating a task, so implementing controllers have to be aware of
      * preexisting tasks.
      */
-    public abstract void maybeTrackTaskState(TaskStatus taskStatus);
+    public abstract void maybeStartTrackingTask(TaskStatus taskStatus);
     /**
      * Remove task - this will happen if the task is cancelled, completed, etc.
      */
-    public abstract void removeTaskStateIfTracked(TaskStatus taskStatus);
+    public abstract void maybeStopTrackingTask(TaskStatus taskStatus);
 
 }
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
index d96fedc..b7f84ec 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -16,17 +16,18 @@
 
 package com.android.server.task.controllers;
 
+import android.app.task.Task;
 import android.content.ComponentName;
-import android.content.Task;
-import android.content.pm.PackageParser;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.os.UserHandle;
 
+import java.io.PrintWriter;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Uniquely identifies a task internally.
- * Created from the public {@link android.content.Task} object when it lands on the scheduler.
+ * Created from the public {@link android.app.task.Task} object when it lands on the scheduler.
  * Contains current state of the requirements of the task, as well as a function to evaluate
  * whether it's ready to run.
  * This object is shared among the various controllers - hence why the different fields are atomic.
@@ -36,80 +37,88 @@
  * @hide
  */
 public class TaskStatus {
-    final int taskId;
-    final int userId;
+    final Task task;
     final int uId;
-    final ComponentName component;
-    final Bundle extras;
 
+    /** At reschedule time we need to know whether to update task on disk. */
+    final boolean persisted;
+
+    // Constraints.
     final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
-    final AtomicBoolean timeConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean meteredConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
 
-    private final boolean hasChargingConstraint;
-    private final boolean hasTimingConstraint;
-    private final boolean hasIdleConstraint;
-    private final boolean hasMeteredConstraint;
-    private final boolean hasConnectivityConstraint;
-
+    /**
+     * Earliest point in the future at which this task will be eligible to run. A value of 0
+     * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
+     */
     private long earliestRunTimeElapsedMillis;
+    /**
+     * Latest point in the future at which this task must be run. A value of {@link Long#MAX_VALUE}
+     * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
+     */
     private long latestRunTimeElapsedMillis;
 
-    /** Provide a unique handle to the service that this task will be run on. */
+    private final int numFailures;
+
+    /** Provide a handle to the service that this task will be run on. */
     public int getServiceToken() {
-        return component.hashCode() + userId;
+        return uId;
     }
 
-    /** Generate a TaskStatus object for a given task and uid. */
-    // TODO: reimplement this to reuse these objects instead of creating a new one each time?
-    public static TaskStatus getForTaskAndUser(Task task, int userId, int uId) {
-        return new TaskStatus(task, userId, uId);
-    }
-
-    /** Set up the state of a newly scheduled task. */
-    TaskStatus(Task task, int userId, int uId) {
-        this.taskId = task.getTaskId();
-        this.userId = userId;
-        this.component = task.getService();
-        this.extras = task.getExtras();
+    /** Create a newly scheduled task. */
+    public TaskStatus(Task task, int uId, boolean persisted) {
+        this.task = task;
         this.uId = uId;
+        this.numFailures = 0;
+        this.persisted = persisted;
 
-        hasChargingConstraint = task.isRequireCharging();
-        hasIdleConstraint = task.isRequireDeviceIdle();
-
+        final long elapsedNow = SystemClock.elapsedRealtime();
         // Timing constraints
         if (task.isPeriodic()) {
-            long elapsedNow = SystemClock.elapsedRealtime();
             earliestRunTimeElapsedMillis = elapsedNow;
             latestRunTimeElapsedMillis = elapsedNow + task.getIntervalMillis();
-            hasTimingConstraint = true;
-        } else if (task.getMinLatencyMillis() != 0L || task.getMaxExecutionDelayMillis() != 0L) {
-            earliestRunTimeElapsedMillis = task.getMinLatencyMillis() > 0L ?
-                    task.getMinLatencyMillis() : Long.MAX_VALUE;
-            latestRunTimeElapsedMillis = task.getMaxExecutionDelayMillis() > 0L ?
-                    task.getMaxExecutionDelayMillis() : Long.MAX_VALUE;
-            hasTimingConstraint = true;
         } else {
-            hasTimingConstraint = false;
+            earliestRunTimeElapsedMillis = task.hasEarlyConstraint() ?
+                    elapsedNow + task.getMinLatencyMillis() : 0L;
+            latestRunTimeElapsedMillis = task.hasLateConstraint() ?
+                    elapsedNow + task.getMaxExecutionDelayMillis() : Long.MAX_VALUE;
         }
+    }
 
-        // Networking constraints
-        hasMeteredConstraint = task.getNetworkCapabilities() == Task.NetworkType.UNMETERED;
-        hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
+    public TaskStatus(TaskStatus rescheduling, long newEarliestRuntimeElapsed,
+                      long newLatestRuntimeElapsed, int backoffAttempt) {
+        this.task = rescheduling.task;
+
+        this.uId = rescheduling.getUid();
+        this.persisted = rescheduling.isPersisted();
+        this.numFailures = backoffAttempt;
+
+        earliestRunTimeElapsedMillis = newEarliestRuntimeElapsed;
+        latestRunTimeElapsedMillis = newLatestRuntimeElapsed;
+    }
+
+    public Task getTask() {
+        return task;
     }
 
     public int getTaskId() {
-        return taskId;
+        return task.getId();
+    }
+
+    public int getNumFailures() {
+        return numFailures;
     }
 
     public ComponentName getServiceComponent() {
-        return component;
+        return task.getService();
     }
 
     public int getUserId() {
-        return userId;
+        return UserHandle.getUserId(uId);
     }
 
     public int getUid() {
@@ -117,53 +126,61 @@
     }
 
     public Bundle getExtras() {
-        return extras;
+        return task.getExtras();
     }
 
-    boolean hasConnectivityConstraint() {
-        return hasConnectivityConstraint;
+    public boolean hasConnectivityConstraint() {
+        return task.getNetworkCapabilities() == Task.NetworkType.ANY;
     }
 
-    boolean hasMeteredConstraint() {
-        return hasMeteredConstraint;
+    public boolean hasMeteredConstraint() {
+        return task.getNetworkCapabilities() == Task.NetworkType.UNMETERED;
     }
 
-    boolean hasChargingConstraint() {
-        return hasChargingConstraint;
+    public boolean hasChargingConstraint() {
+        return task.isRequireCharging();
     }
 
-    boolean hasTimingConstraint() {
-        return hasTimingConstraint;
+    public boolean hasTimingDelayConstraint() {
+        return earliestRunTimeElapsedMillis != 0L;
     }
 
-    boolean hasIdleConstraint() {
-        return hasIdleConstraint;
+    public boolean hasDeadlineConstraint() {
+        return latestRunTimeElapsedMillis != Long.MAX_VALUE;
     }
 
-    long getEarliestRunTime() {
+    public boolean hasIdleConstraint() {
+        return task.isRequireDeviceIdle();
+    }
+
+    public long getEarliestRunTime() {
         return earliestRunTimeElapsedMillis;
     }
 
-    long getLatestRunTime() {
+    public long getLatestRunTimeElapsed() {
         return latestRunTimeElapsedMillis;
     }
 
+    public boolean isPersisted() {
+        return persisted;
+    }
     /**
-     * @return whether this task is ready to run, based on its requirements.
+     * @return Whether or not this task is ready to run, based on its requirements.
      */
     public synchronized boolean isReady() {
-        return (!hasChargingConstraint || chargingConstraintSatisfied.get())
-                && (!hasTimingConstraint || timeConstraintSatisfied.get())
-                && (!hasConnectivityConstraint || connectivityConstraintSatisfied.get())
-                && (!hasMeteredConstraint || meteredConstraintSatisfied.get())
-                && (!hasIdleConstraint || idleConstraintSatisfied.get());
+        return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
+                && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
+                && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
+                && (!hasMeteredConstraint() || meteredConstraintSatisfied.get())
+                && (!hasIdleConstraint() || idleConstraintSatisfied.get())
+                && (!hasDeadlineConstraint() || deadlineConstraintSatisfied.get());
     }
 
     @Override
     public int hashCode() {
-        int result = component.hashCode();
-        result = 31 * result + taskId;
-        result = 31 * result + userId;
+        int result = getServiceComponent().hashCode();
+        result = 31 * result + task.getId();
+        result = 31 * result + uId;
         return result;
     }
 
@@ -173,8 +190,15 @@
         if (!(o instanceof TaskStatus)) return false;
 
         TaskStatus that = (TaskStatus) o;
-        return ((taskId == that.taskId)
-                && (userId == that.userId)
-                && (component.equals(that.component)));
+        return ((task.getId() == that.task.getId())
+                && (uId == that.uId)
+                && (getServiceComponent().equals(that.getServiceComponent())));
+    }
+
+    // Dumpsys infrastructure
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("Task "); pw.println(task.getId());
+        pw.print(prefix); pw.print("uid="); pw.println(uId);
+        pw.print(prefix); pw.print("component="); pw.println(task.getService());
     }
 }
diff --git a/services/core/java/com/android/server/task/controllers/TimeController.java b/services/core/java/com/android/server/task/controllers/TimeController.java
index 6d97a53..72f312c 100644
--- a/services/core/java/com/android/server/task/controllers/TimeController.java
+++ b/services/core/java/com/android/server/task/controllers/TimeController.java
@@ -23,7 +23,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.SystemClock;
-import android.util.Log;
 
 import com.android.server.task.TaskManagerService;
 
@@ -54,8 +53,17 @@
     private AlarmManager mAlarmService = null;
     /** List of tracked tasks, sorted asc. by deadline */
     private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+    /** Singleton. */
+    private static TimeController mSingleton;
 
-    public TimeController(TaskManagerService service) {
+    public static synchronized TimeController get(TaskManagerService taskManager) {
+        if (mSingleton == null) {
+            mSingleton = new TimeController(taskManager);
+        }
+        return mSingleton;
+    }
+
+    private TimeController(TaskManagerService service) {
         super(service);
         mTaskExpiredAlarmIntent =
                 PendingIntent.getBroadcast(mContext, 0 /* ignored */,
@@ -75,8 +83,8 @@
      * list.
      */
     @Override
-    public synchronized void maybeTrackTaskState(TaskStatus task) {
-        if (task.hasTimingConstraint()) {
+    public synchronized void maybeStartTrackingTask(TaskStatus task) {
+        if (task.hasTimingDelayConstraint()) {
             ListIterator<TaskStatus> it = mTrackedTasks.listIterator(mTrackedTasks.size());
             while (it.hasPrevious()) {
                 TaskStatus ts = it.previous();
@@ -85,13 +93,13 @@
                     it.remove();
                     it.add(task);
                     break;
-                } else if (ts.getLatestRunTime() < task.getLatestRunTime()) {
+                } else if (ts.getLatestRunTimeElapsed() < task.getLatestRunTimeElapsed()) {
                     // Insert
                     it.add(task);
                     break;
                 }
             }
-            maybeUpdateAlarms(task.getEarliestRunTime(), task.getLatestRunTime());
+            maybeUpdateAlarms(task.getEarliestRunTime(), task.getLatestRunTimeElapsed());
         }
     }
 
@@ -100,12 +108,12 @@
      * so, update them.
      */
     @Override
-    public synchronized void removeTaskStateIfTracked(TaskStatus taskStatus) {
+    public synchronized void maybeStopTrackingTask(TaskStatus taskStatus) {
         if (mTrackedTasks.remove(taskStatus)) {
             if (mNextDelayExpiredElapsedMillis <= taskStatus.getEarliestRunTime()) {
                 handleTaskDelayExpired();
             }
-            if (mNextTaskExpiredElapsedMillis <= taskStatus.getLatestRunTime()) {
+            if (mNextTaskExpiredElapsedMillis <= taskStatus.getLatestRunTimeElapsed()) {
                 handleTaskDeadlineExpired();
             }
         }
@@ -140,10 +148,10 @@
      * back and forth.
      */
     private boolean canStopTrackingTask(TaskStatus taskStatus) {
-        final long elapsedNowMillis = SystemClock.elapsedRealtime();
-        return taskStatus.timeConstraintSatisfied.get() &&
-                (taskStatus.getLatestRunTime() == Long.MAX_VALUE ||
-                        taskStatus.getLatestRunTime() < elapsedNowMillis);
+        return (!taskStatus.hasTimingDelayConstraint() ||
+                taskStatus.timeDelayConstraintSatisfied.get()) &&
+                (!taskStatus.hasDeadlineConstraint() ||
+                        taskStatus.deadlineConstraintSatisfied.get());
     }
 
     private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
@@ -174,10 +182,10 @@
         Iterator<TaskStatus> it = mTrackedTasks.iterator();
         while (it.hasNext()) {
             TaskStatus ts = it.next();
-            final long taskDeadline = ts.getLatestRunTime();
+            final long taskDeadline = ts.getLatestRunTimeElapsed();
 
             if (taskDeadline <= nowElapsedMillis) {
-                ts.timeConstraintSatisfied.set(true);
+                ts.deadlineConstraintSatisfied.set(true);
                 mStateChangedListener.onTaskDeadlineExpired(ts);
                 it.remove();
             } else {  // Sorted by expiry time, so take the next one and stop.
@@ -199,10 +207,12 @@
         Iterator<TaskStatus> it = mTrackedTasks.iterator();
         while (it.hasNext()) {
             final TaskStatus ts = it.next();
+            if (!ts.hasTimingDelayConstraint()) {
+                continue;
+            }
             final long taskDelayTime = ts.getEarliestRunTime();
             if (taskDelayTime < nowElapsedMillis) {
-                ts.timeConstraintSatisfied.set(true);
-                mStateChangedListener.onTaskStateChanged(ts);
+                ts.timeDelayConstraintSatisfied.set(true);
                 if (canStopTrackingTask(ts)) {
                     it.remove();
                 }
@@ -212,6 +222,7 @@
                 }
             }
         }
+        mStateChangedListener.onControllerStateChanged();
         maybeUpdateAlarms(nextDelayTime, Long.MAX_VALUE);
     }
 
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 47ce3b6..f18939f 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -63,6 +63,11 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_GRANT_TRUST:
+                    if (!isConnected()) {
+                        Log.w(TAG, "Agent is not connected, cannot grant trust: "
+                                + mName.flattenToShortString());
+                        return;
+                    }
                     mTrusted = true;
                     mMessage = (CharSequence) msg.obj;
                     boolean initiatedByUser = msg.arg1 != 0;
@@ -119,6 +124,7 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
             mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
+            mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
             setCallback(mCallback);
         }
 
@@ -179,7 +185,10 @@
 
     public void unbind() {
         if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
+        mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
         mContext.unbindService(mConnection);
+        mTrustAgentService = null;
+        mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
     }
 
     public boolean isConnected() {
diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java
index aad156c..56950d2 100644
--- a/services/core/java/com/android/server/trust/TrustArchive.java
+++ b/services/core/java/com/android/server/trust/TrustArchive.java
@@ -33,6 +33,8 @@
     private static final int TYPE_REVOKE_TRUST = 1;
     private static final int TYPE_TRUST_TIMEOUT = 2;
     private static final int TYPE_AGENT_DIED = 3;
+    private static final int TYPE_AGENT_CONNECTED = 4;
+    private static final int TYPE_AGENT_STOPPED = 5;
 
     private static final int HISTORY_LIMIT = 200;
 
@@ -79,6 +81,14 @@
         addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, false));
     }
 
+    public void logAgentConnected(int userId, ComponentName agent) {
+        addEvent(new Event(TYPE_AGENT_CONNECTED, userId, agent, null, 0, false));
+    }
+
+    public void logAgentStopped(int userId, ComponentName agent) {
+        addEvent(new Event(TYPE_AGENT_STOPPED, userId, agent, null, 0, false));
+    }
+
     private void addEvent(Event e) {
         if (mEvents.size() >= HISTORY_LIMIT) {
             mEvents.removeFirst();
@@ -152,6 +162,10 @@
                 return "TrustTimeout";
             case TYPE_AGENT_DIED:
                 return "AgentDied";
+            case TYPE_AGENT_CONNECTED:
+                return "AgentConnected";
+            case TYPE_AGENT_STOPPED:
+                return "AgentStopped";
             default:
                 return "Unknown(" + type + ")";
         }
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
new file mode 100644
index 0000000..4bdd2be
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -0,0 +1,128 @@
+/*
+ * 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 com.android.server.tv;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.tv.TvInputHardwareInfo;
+import android.tv.TvStreamConfig;
+import android.view.Surface;
+
+/**
+ * Provides access to the low-level TV input hardware abstraction layer.
+ */
+final class TvInputHal {
+    public final static int SUCCESS = 0;
+    public final static int ERROR_NO_INIT = -1;
+    public final static int ERROR_STALE_CONFIG = -2;
+    public final static int ERROR_UNKNOWN = -3;
+
+    public static final int TYPE_HDMI = 1;
+    public static final int TYPE_BUILT_IN_TUNER = 2;
+    public static final int TYPE_PASSTHROUGH = 3;
+
+    public interface Callback {
+        public void onDeviceAvailable(
+                TvInputHardwareInfo info, TvStreamConfig[] configs);
+        public void onDeviceUnavailable(int deviceId);
+        public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
+    }
+
+    private native long nativeOpen();
+
+    private static native int nativeSetSurface(long ptr, int deviceId, int streamId,
+            Surface surface);
+    private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
+            int generation);
+    private static native void nativeClose(long ptr);
+
+    private long mPtr = 0l;
+    private final Callback mCallback;
+    private final HandlerThread mThread = new HandlerThread("TV input HAL event thread");
+    private final Handler mHandler;
+    private int mStreamConfigGeneration = 0;
+    private TvStreamConfig[] mStreamConfigs;
+
+    public TvInputHal(Callback callback) {
+        mCallback = callback;
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+    }
+
+    public void init() {
+        mPtr = nativeOpen();
+    }
+
+    public int setSurface(int deviceId, Surface surface, TvStreamConfig streamConfig) {
+        if (mPtr == 0) {
+            return ERROR_NO_INIT;
+        }
+        if (mStreamConfigGeneration != streamConfig.getGeneration()) {
+            return ERROR_STALE_CONFIG;
+        }
+        if (nativeSetSurface(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
+            return SUCCESS;
+        } else {
+            return ERROR_UNKNOWN;
+        }
+    }
+
+    public void close() {
+        if (mPtr != 0l) {
+            nativeClose(mPtr);
+            mThread.quitSafely();
+        }
+    }
+
+    private synchronized void retrieveStreamConfigs(int deviceId) {
+        ++mStreamConfigGeneration;
+        mStreamConfigs = nativeGetStreamConfigs(mPtr, deviceId, mStreamConfigGeneration);
+    }
+
+    // Called from native
+    private void deviceAvailableFromNative(int deviceId, int type) {
+        final TvInputHardwareInfo info = new TvInputHardwareInfo(deviceId, type);
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                retrieveStreamConfigs(info.getDeviceId());
+                mCallback.onDeviceAvailable(info, mStreamConfigs);
+            }
+        });
+    }
+
+    private void deviceUnavailableFromNative(int deviceId) {
+        final int id = deviceId;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mCallback.onDeviceUnavailable(id);
+            }
+        });
+    }
+
+    private void streamConfigsChangedFromNative(int deviceId) {
+        final int id = deviceId;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                retrieveStreamConfigs(id);
+                mCallback.onStreamConfigurationChanged(id, mStreamConfigs);
+            }
+        });
+    }
+}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
new file mode 100644
index 0000000..b95b0f0
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -0,0 +1,308 @@
+/*
+ * 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.tv;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.tv.ITvInputHardware;
+import android.tv.ITvInputHardwareCallback;
+import android.tv.TvInputHardwareInfo;
+import android.tv.TvStreamConfig;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A helper class for TvInputManagerService to handle TV input hardware.
+ *
+ * This class does a basic connection management and forwarding calls to TvInputHal which eventually
+ * calls to tv_input HAL module.
+ *
+ * @hide
+ */
+class TvInputHardwareManager implements TvInputHal.Callback {
+    private static final String TAG = TvInputHardwareManager.class.getSimpleName();
+    private final TvInputHal mHal = new TvInputHal(this);
+    private final SparseArray<Connection> mConnections = new SparseArray<Connection>();
+    private final List<TvInputHardwareInfo> mInfoList = new ArrayList<TvInputHardwareInfo>();
+    private final Context mContext;
+    private final Set<Integer> mActiveHdmiSources = new HashSet<Integer>();
+
+    private final Object mLock = new Object();
+
+    public TvInputHardwareManager(Context context) {
+        mContext = context;
+        // TODO(hdmi): mHdmiManager = mContext.getSystemService(...);
+        // TODO(hdmi): mHdmiClient = mHdmiManager.getTvClient();
+        mHal.init();
+    }
+
+    @Override
+    public void onDeviceAvailable(
+            TvInputHardwareInfo info, TvStreamConfig[] configs) {
+        synchronized (mLock) {
+            Connection connection = new Connection(info);
+            connection.updateConfigsLocked(configs);
+            mConnections.put(info.getDeviceId(), connection);
+            buildInfoListLocked();
+            // TODO: notify if necessary
+        }
+    }
+
+    private void buildInfoListLocked() {
+        mInfoList.clear();
+        for (int i = 0; i < mConnections.size(); ++i) {
+            mInfoList.add(mConnections.valueAt(i).getInfoLocked());
+        }
+    }
+
+    @Override
+    public void onDeviceUnavailable(int deviceId) {
+        synchronized (mLock) {
+            Connection connection = mConnections.get(deviceId);
+            if (connection == null) {
+                Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);
+                return;
+            }
+            connection.resetLocked(null, null, null, null);
+            mConnections.remove(deviceId);
+            buildInfoListLocked();
+            // TODO: notify if necessary
+        }
+    }
+
+    @Override
+    public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) {
+        synchronized (mLock) {
+            Connection connection = mConnections.get(deviceId);
+            if (connection == null) {
+                Slog.e(TAG, "StreamConfigurationChanged: Cannot find a connection with "
+                        + deviceId);
+                return;
+            }
+            connection.updateConfigsLocked(configs);
+            try {
+                connection.getCallbackLocked().onStreamConfigChanged(configs);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "onStreamConfigurationChanged: " + e);
+            }
+        }
+    }
+
+    public List<TvInputHardwareInfo> getHardwareList() {
+        synchronized (mLock) {
+            return mInfoList;
+        }
+    }
+
+    /**
+     * Create a TvInputHardware object with a specific deviceId. One service at a time can access
+     * the object, and if more than one process attempts to create hardware with the same deviceId,
+     * the latest service will get the object and all the other hardware are released. The
+     * release is notified via ITvInputHardwareCallback.onReleased().
+     */
+    public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback,
+            int callingUid, int resolvedUserId) {
+        if (callback == null) {
+            throw new NullPointerException();
+        }
+        synchronized (mLock) {
+            Connection connection = mConnections.get(deviceId);
+            if (connection == null) {
+                Slog.e(TAG, "Invalid deviceId : " + deviceId);
+                return null;
+            }
+            if (connection.getCallingUidLocked() != callingUid
+                    || connection.getResolvedUserIdLocked() != resolvedUserId) {
+                TvInputHardwareImpl hardware = new TvInputHardwareImpl(connection.getInfoLocked());
+                try {
+                    callback.asBinder().linkToDeath(connection, 0);
+                } catch (RemoteException e) {
+                    hardware.release();
+                    return null;
+                }
+                connection.resetLocked(hardware, callback, callingUid, resolvedUserId);
+            }
+            return connection.getHardwareLocked();
+        }
+    }
+
+    /**
+     * Release the specified hardware.
+     */
+    public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid,
+            int resolvedUserId) {
+        synchronized (mLock) {
+            Connection connection = mConnections.get(deviceId);
+            if (connection == null) {
+                Slog.e(TAG, "Invalid deviceId : " + deviceId);
+                return;
+            }
+            if (connection.getHardwareLocked() != hardware
+                    || connection.getCallingUidLocked() != callingUid
+                    || connection.getResolvedUserIdLocked() != resolvedUserId) {
+                return;
+            }
+            connection.resetLocked(null, null, null, null);
+        }
+    }
+
+    private class Connection implements IBinder.DeathRecipient {
+        private final TvInputHardwareInfo mInfo;
+        private TvInputHardwareImpl mHardware = null;
+        private ITvInputHardwareCallback mCallback;
+        private TvStreamConfig[] mConfigs = null;
+        private Integer mCallingUid = null;
+        private Integer mResolvedUserId = null;
+
+        public Connection(TvInputHardwareInfo info) {
+            mInfo = info;
+        }
+
+        // *Locked methods assume TvInputHardwareManager.mLock is held.
+
+        public void resetLocked(TvInputHardwareImpl hardware,
+                ITvInputHardwareCallback callback, Integer callingUid, Integer resolvedUserId) {
+            if (mHardware != null) {
+                try {
+                    mCallback.onReleased();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Connection::resetHardware: " + e);
+                }
+                mHardware.release();
+            }
+            mHardware = hardware;
+            mCallback = callback;
+            mCallingUid = callingUid;
+            mResolvedUserId = resolvedUserId;
+
+            if (mHardware != null && mCallback != null) {
+                try {
+                    mCallback.onStreamConfigChanged(getConfigsLocked());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Connection::resetHardware: " + e);
+                }
+            }
+        }
+
+        public void updateConfigsLocked(TvStreamConfig[] configs) {
+            mConfigs = configs;
+        }
+
+        public TvInputHardwareInfo getInfoLocked() {
+            return mInfo;
+        }
+
+        public ITvInputHardware getHardwareLocked() {
+            return mHardware;
+        }
+
+        public ITvInputHardwareCallback getCallbackLocked() {
+            return mCallback;
+        }
+
+        public TvStreamConfig[] getConfigsLocked() {
+            return mConfigs;
+        }
+
+        public int getCallingUidLocked() {
+            return mCallingUid;
+        }
+
+        public int getResolvedUserIdLocked() {
+            return mResolvedUserId;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                resetLocked(null, null, null, null);
+            }
+        }
+    }
+
+    private class TvInputHardwareImpl extends ITvInputHardware.Stub {
+        private final TvInputHardwareInfo mInfo;
+        private boolean mReleased = false;
+        private final Object mImplLock = new Object();
+
+        public TvInputHardwareImpl(TvInputHardwareInfo info) {
+            mInfo = info;
+        }
+
+        public void release() {
+            synchronized (mImplLock) {
+                mReleased = true;
+            }
+        }
+
+        @Override
+        public boolean setSurface(Surface surface, TvStreamConfig config)
+                throws RemoteException {
+            synchronized (mImplLock) {
+                if (mReleased) {
+                    throw new IllegalStateException("Device already released.");
+                }
+                if (mInfo.getType() == TvInputHal.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);
+                        }
+                    }
+                }
+                return mHal.setSurface(mInfo.getDeviceId(), surface, config) == TvInputHal.SUCCESS;
+            }
+        }
+
+        @Override
+        public void setVolume(float volume) throws RemoteException {
+            synchronized (mImplLock) {
+                if (mReleased) {
+                    throw new IllegalStateException("Device already released.");
+                }
+            }
+            // TODO
+        }
+
+        @Override
+        public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException {
+            synchronized (mImplLock) {
+                if (mReleased) {
+                    throw new IllegalStateException("Device already released.");
+                }
+            }
+            if (mInfo.getType() != TvInputHal.TYPE_HDMI) {
+                return false;
+            }
+            // TODO(hdmi): mHdmiClient.sendKeyEvent(event);
+            return false;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 8ad7fff..6c38a4c 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -42,11 +42,14 @@
 import android.os.UserHandle;
 import android.provider.TvContract;
 import android.tv.ITvInputClient;
+import android.tv.ITvInputHardware;
+import android.tv.ITvInputHardwareCallback;
 import android.tv.ITvInputManager;
 import android.tv.ITvInputService;
 import android.tv.ITvInputServiceCallback;
 import android.tv.ITvInputSession;
 import android.tv.ITvInputSessionCallback;
+import android.tv.TvInputHardwareInfo;
 import android.tv.TvInputInfo;
 import android.tv.TvInputService;
 import android.util.Slog;
@@ -71,6 +74,7 @@
     private static final String TAG = "TvInputManagerService";
 
     private final Context mContext;
+    private final TvInputHardwareManager mTvInputHardwareManager;
 
     private final ContentResolver mContentResolver;
 
@@ -92,6 +96,7 @@
         mContentResolver = context.getContentResolver();
         mLogHandler = new LogHandler(IoThread.get().getLooper());
 
+        mTvInputHardwareManager = new TvInputHardwareManager(context);
         registerBroadcastReceivers();
 
         synchronized (mLock) {
@@ -730,6 +735,64 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
+            if (mContext.checkCallingPermission(
+                    android.Manifest.permission.TV_INPUT_HARDWARE)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return null;
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return mTvInputHardwareManager.getHardwareList();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public ITvInputHardware acquireTvInputHardware(int deviceId,
+                ITvInputHardwareCallback callback, int userId) throws RemoteException {
+            if (mContext.checkCallingPermission(
+                    android.Manifest.permission.TV_INPUT_HARDWARE)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return null;
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "acquireTvInputHardware");
+            try {
+                return mTvInputHardwareManager.acquireHardware(
+                        deviceId, callback, callingUid, resolvedUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
+                throws RemoteException {
+            if (mContext.checkCallingPermission(
+                    android.Manifest.permission.TV_INPUT_HARDWARE)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "releaseTvInputHardware");
+            try {
+                mTvInputHardwareManager.releaseHardware(
+                        deviceId, hardware, callingUid, resolvedUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     }
 
     private static final class UserState {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 97a42a4..96b5672 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3189,6 +3189,7 @@
             WindowState win = atoken.findMainWindow();
             Rect containingFrame = new Rect(0, 0, width, height);
             Rect contentInsets = new Rect();
+            boolean isFullScreen = true;
             if (win != null) {
                 if (win.mContainingFrame != null) {
                     containingFrame.set(win.mContainingFrame);
@@ -3196,11 +3197,11 @@
                 if (win.mContentInsets != null) {
                     contentInsets.set(win.mContentInsets);
                 }
+                isFullScreen =
+                        ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) ==
+                                SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
             }
 
-            boolean isFullScreen =
-                    ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
-                            == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
             Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
                     mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen);
             if (a != null) {
@@ -10267,6 +10268,10 @@
         mPolicy.lockNow(options);
     }
 
+    public void showRecentApps() {
+        mPolicy.showRecentApps();
+    }
+
     @Override
     public boolean isSafeModeEnabled() {
         return mSafeMode;
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 51583a5..3cfb45b 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -23,6 +23,7 @@
     $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
     $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
     $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
     $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
new file mode 100644
index 0000000..f0c4f3a
--- /dev/null
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "TvInputHal"
+
+//#define LOG_NDEBUG 0
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_view_Surface.h"
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <gui/Surface.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <hardware/tv_input.h>
+
+namespace android {
+
+static struct {
+    jmethodID deviceAvailable;
+    jmethodID deviceUnavailable;
+    jmethodID streamConfigsChanged;
+} gTvInputHalClassInfo;
+
+static struct {
+    jclass clazz;
+} gTvStreamConfigClassInfo;
+
+static struct {
+    jclass clazz;
+
+    jmethodID constructor;
+    jmethodID streamId;
+    jmethodID type;
+    jmethodID maxWidth;
+    jmethodID maxHeight;
+    jmethodID generation;
+    jmethodID build;
+} gTvStreamConfigBuilderClassInfo;
+
+////////////////////////////////////////////////////////////////////////////////
+
+class JTvInputHal {
+public:
+    ~JTvInputHal();
+
+    static JTvInputHal* createInstance(JNIEnv* env, jobject thiz);
+
+    int setSurface(int deviceId, int streamId, const sp<Surface>& surface);
+    void getStreamConfigs(int deviceId, jobjectArray* array);
+    const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
+
+private:
+    class Connection {
+    public:
+        Connection() : mStreamId(0) {}
+
+        sp<Surface> mSurface;
+        sp<NativeHandle> mSourceHandle;
+        int mStreamId;
+    };
+
+    JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev);
+
+    static void notify(
+            tv_input_device_t* dev,tv_input_event_t* event, void* data);
+
+    void onDeviceAvailable(const tv_input_device_info_t& info);
+    void onDeviceUnavailable(int deviceId);
+    void onStreamConfigurationsChanged(int deviceId);
+
+    jweak mThiz;
+    tv_input_device_t* mDevice;
+    tv_input_callback_ops_t mCallback;
+
+    KeyedVector<int, Connection> mConnections;
+};
+
+JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device) {
+    mThiz = env->NewWeakGlobalRef(thiz);
+    mDevice = device;
+    mCallback.notify = &JTvInputHal::notify;
+
+    mDevice->initialize(mDevice, &mCallback, this);
+}
+
+JTvInputHal::~JTvInputHal() {
+    mDevice->common.close((hw_device_t*)mDevice);
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->DeleteWeakGlobalRef(mThiz);
+    mThiz = NULL;
+}
+
+JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) {
+    tv_input_module_t* module = NULL;
+    status_t err = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID,
+            (hw_module_t const**)&module);
+    if (err) {
+        ALOGE("Couldn't load %s module (%s)",
+                TV_INPUT_HARDWARE_MODULE_ID, strerror(-err));
+        return 0;
+    }
+
+    tv_input_device_t* device = NULL;
+    err = module->common.methods->open(
+            (hw_module_t*)module,
+            TV_INPUT_DEFAULT_DEVICE,
+            (hw_device_t**)&device);
+    if (err) {
+        ALOGE("Couldn't open %s device (%s)",
+                TV_INPUT_DEFAULT_DEVICE, strerror(-err));
+        return 0;
+    }
+
+    return new JTvInputHal(env, thiz, device);
+}
+
+int JTvInputHal::setSurface(int deviceId, int streamId, const sp<Surface>& surface) {
+    Connection& connection = mConnections.editValueFor(deviceId);
+    if (connection.mStreamId == streamId && connection.mSurface == surface) {
+        // Nothing to do
+        return NO_ERROR;
+    }
+    if (Surface::isValid(connection.mSurface)) {
+        connection.mSurface.clear();
+    }
+    if (surface == NULL) {
+        if (connection.mSurface != NULL) {
+            connection.mSurface->setSidebandStream(NULL);
+            connection.mSurface.clear();
+        }
+        if (connection.mSourceHandle != NULL) {
+            // Need to reset streams
+            if (mDevice->close_stream(
+                    mDevice, deviceId, connection.mStreamId) != 0) {
+                ALOGE("Couldn't remove stream");
+                return BAD_VALUE;
+            }
+            connection.mSourceHandle.clear();
+        }
+        return NO_ERROR;
+    }
+    connection.mSurface = surface;
+    if (connection.mSourceHandle == NULL) {
+        // Need to configure stream
+        int numConfigs = 0;
+        const tv_stream_config_t* configs = NULL;
+        if (mDevice->get_stream_configurations(
+                mDevice, deviceId, &numConfigs, &configs) != 0) {
+            ALOGE("Couldn't get stream configs");
+            return UNKNOWN_ERROR;
+        }
+        int configIndex = -1;
+        for (int i = 0; i < numConfigs; ++i) {
+            if (configs[i].stream_id == streamId) {
+                configIndex = i;
+                break;
+            }
+        }
+        if (configIndex == -1) {
+            ALOGE("Cannot find a config with given stream ID: %d", streamId);
+            return BAD_VALUE;
+        }
+        // TODO: handle buffer producer profile.
+        if (configs[configIndex].type !=
+                TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
+            ALOGE("Profiles other than independent video source is not yet "
+                  "supported : type = %d", configs[configIndex].type);
+            return INVALID_OPERATION;
+        }
+        tv_stream_t stream;
+        stream.stream_id = configs[configIndex].stream_id;
+        if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
+            ALOGE("Couldn't add stream");
+            return UNKNOWN_ERROR;
+        }
+        connection.mSourceHandle = NativeHandle::create(
+                stream.sideband_stream_source_handle, false);
+        connection.mStreamId = stream.stream_id;
+        connection.mSurface->setSidebandStream(connection.mSourceHandle);
+    }
+    return NO_ERROR;
+}
+
+const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
+    const tv_stream_config_t* configs = NULL;
+    if (mDevice->get_stream_configurations(
+            mDevice, deviceId, numConfigs, &configs) != 0) {
+        ALOGE("Couldn't get stream configs");
+        return NULL;
+    }
+    return configs;
+}
+
+
+// static
+void JTvInputHal::notify(
+        tv_input_device_t* dev, tv_input_event_t* event, void* data) {
+    JTvInputHal* thiz = (JTvInputHal*)data;
+    switch (event->type) {
+        case TV_INPUT_EVENT_DEVICE_AVAILABLE: {
+            thiz->onDeviceAvailable(event->device_info);
+        } break;
+        case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {
+            thiz->onDeviceUnavailable(event->device_info.device_id);
+        } break;
+        case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: {
+            thiz->onStreamConfigurationsChanged(event->device_info.device_id);
+        } break;
+        default:
+            ALOGE("Unrecognizable event");
+    }
+}
+
+void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    mConnections.add(info.device_id, Connection());
+    env->CallVoidMethod(
+            mThiz,
+            gTvInputHalClassInfo.deviceAvailable,
+            info.device_id,
+            info.type);
+}
+
+void JTvInputHal::onDeviceUnavailable(int deviceId) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    mConnections.removeItem(deviceId);
+    env->CallVoidMethod(
+            mThiz,
+            gTvInputHalClassInfo.deviceUnavailable,
+            deviceId);
+}
+
+void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    mConnections.removeItem(deviceId);
+    env->CallVoidMethod(
+            mThiz,
+            gTvInputHalClassInfo.streamConfigsChanged,
+            deviceId);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static jlong nativeOpen(JNIEnv* env, jobject thiz) {
+    return (jlong)JTvInputHal::createInstance(env, thiz);
+}
+
+static int nativeSetSurface(JNIEnv* env, jclass clazz,
+        jlong ptr, jint deviceId, jint streamId, jobject jsurface) {
+    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
+    sp<Surface> surface(
+            jsurface
+            ? android_view_Surface_getSurface(env, jsurface)
+            : NULL);
+    return tvInputHal->setSurface(deviceId, streamId, surface);
+}
+
+static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
+        jlong ptr, jint deviceId, jint generation) {
+    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
+    int numConfigs = 0;
+    const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
+
+    jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
+    for (int i = 0; i < numConfigs; ++i) {
+        jobject builder = env->NewObject(
+                gTvStreamConfigBuilderClassInfo.clazz,
+                gTvStreamConfigBuilderClassInfo.constructor);
+        env->CallObjectMethod(
+                builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
+        env->CallObjectMethod(
+                builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
+        env->CallObjectMethod(
+                builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
+        env->CallObjectMethod(
+                builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
+        env->CallObjectMethod(
+                builder, gTvStreamConfigBuilderClassInfo.generation, generation);
+
+        jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);
+
+        env->SetObjectArrayElement(result, i, config);
+
+        env->DeleteLocalRef(config);
+        env->DeleteLocalRef(builder);
+    }
+    return result;
+}
+
+static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
+    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
+    delete tvInputHal;
+}
+
+static JNINativeMethod gTvInputHalMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeOpen", "()J",
+            (void*) nativeOpen },
+    { "nativeSetSurface", "(JIILandroid/view/Surface;)I",
+            (void*) nativeSetSurface },
+    { "nativeGetStreamConfigs", "(JII)[Landroid/tv/TvStreamConfig;",
+            (void*) nativeGetStreamConfigs },
+    { "nativeClose", "(J)V",
+            (void*) nativeClose },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className)
+
+#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method" methodName)
+
+int register_android_server_tv_TvInputHal(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal",
+            gTvInputHalMethods, NELEM(gTvInputHalMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    jclass clazz;
+    FIND_CLASS(clazz, "com/android/server/tv/TvInputHal");
+
+    GET_METHOD_ID(
+            gTvInputHalClassInfo.deviceAvailable, clazz, "deviceAvailableFromNative", "(II)V");
+    GET_METHOD_ID(
+            gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
+    GET_METHOD_ID(
+            gTvInputHalClassInfo.streamConfigsChanged, clazz,
+            "streamConfigsChangedFromNative", "(I)V");
+
+    FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/tv/TvStreamConfig");
+    gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz));
+
+    FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/tv/TvStreamConfig$Builder");
+    gTvStreamConfigBuilderClassInfo.clazz =
+            jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz));
+
+    GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.constructor,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "<init>", "()V");
+    GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.streamId,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "streamId", "(I)Landroid/tv/TvStreamConfig$Builder;");
+    GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.type,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "type", "(I)Landroid/tv/TvStreamConfig$Builder;");
+    GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.maxWidth,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "maxWidth", "(I)Landroid/tv/TvStreamConfig$Builder;");
+    GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.maxHeight,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "maxHeight", "(I)Landroid/tv/TvStreamConfig$Builder;");
+    GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.generation,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "generation", "(I)Landroid/tv/TvStreamConfig$Builder;");
+    GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.build,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "build", "()Landroid/tv/TvStreamConfig;");
+
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1feb325..bfa8286 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,6 +41,7 @@
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
 int register_android_server_hdmi_HdmiCecService(JNIEnv* env);
 int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
+int register_android_server_tv_TvInputHal(JNIEnv* env);
 };
 
 using namespace android;
@@ -78,6 +79,7 @@
     // TODO: remove this once replaces HdmiCecService with HdmiControlService.
     register_android_server_hdmi_HdmiCecService(env);
     register_android_server_hdmi_HdmiMhlController(env);
+    register_android_server_tv_TvInputHal(env);
 
     return JNI_VERSION_1_4;
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5395f60..d78fb13 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3303,7 +3303,7 @@
         }
     }
 
-    public void addForwardingIntentFilter(ComponentName who, IntentFilter filter, int flags) {
+    public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
@@ -3314,12 +3314,12 @@
             IPackageManager pm = AppGlobals.getPackageManager();
             long id = Binder.clearCallingIdentity();
             try {
-                if ((flags & DevicePolicyManager.FLAG_TO_PRIMARY_USER) != 0) {
-                    pm.addForwardingIntentFilter(filter, true /*removable*/, callingUserId,
+                if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) {
+                    pm.addCrossProfileIntentFilter(filter, true /*removable*/, callingUserId,
                             UserHandle.USER_OWNER);
                 }
-                if ((flags & DevicePolicyManager.FLAG_TO_MANAGED_PROFILE) != 0) {
-                    pm.addForwardingIntentFilter(filter, true /*removable*/, UserHandle.USER_OWNER,
+                if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) {
+                    pm.addCrossProfileIntentFilter(filter, true /*removable*/, UserHandle.USER_OWNER,
                             callingUserId);
                 }
             } catch (RemoteException re) {
@@ -3330,7 +3330,7 @@
         }
     }
 
-    public void clearForwardingIntentFilters(ComponentName who) {
+    public void clearCrossProfileIntentFilters(ComponentName who) {
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
@@ -3340,8 +3340,8 @@
             IPackageManager pm = AppGlobals.getPackageManager();
             long id = Binder.clearCallingIdentity();
             try {
-                pm.clearForwardingIntentFilters(callingUserId);
-                pm.clearForwardingIntentFilters(UserHandle.USER_OWNER);
+                pm.clearCrossProfileIntentFilters(callingUserId);
+                pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER);
             } catch (RemoteException re) {
                 // Shouldn't happen
             } finally {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de46b16..bc34e0e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,6 +83,7 @@
 import com.android.server.search.SearchManagerService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.task.TaskManagerService;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.twilight.TwilightService;
@@ -132,6 +133,8 @@
             "com.android.server.hdmi.HdmiCecService";
     private static final String ETHERNET_SERVICE_CLASS =
             "com.android.server.ethernet.EthernetService";
+    private static final String TASK_SERVICE_CLASS =
+            "com.android.server.task.TaskManagerService";
 
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
@@ -831,6 +834,8 @@
 
             mSystemServiceManager.startService(UiModeManagerService.class);
 
+            mSystemServiceManager.startService(TaskManagerService.class);
+
             if (!disableNonCoreServices) {
                 try {
                     if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4aed1fe..2483419 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1752,6 +1752,8 @@
      *
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return The logical channel id which is negative on error.
+     *
+     * @hide
      */
     public int iccOpenLogicalChannel(String AID) {
         try {
@@ -1773,6 +1775,8 @@
      * @param channel is the channel id to be closed as retruned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
+     *
+     * @hide
      */
     public boolean iccCloseLogicalChannel(int channel) {
         try {
@@ -1802,6 +1806,8 @@
      * @param data Data to be sent with the APDU.
      * @return The APDU response from the ICC card with the status appended at
      *            the end. If an error occurs, an empty string is returned.
+     *
+     * @hide
      */
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
@@ -1826,6 +1832,8 @@
      * @return The APDU response from the ICC card, with the last 4 bytes
      *         being the status word. If the command fails, returns an empty
      *         string.
+     *
+     * @hide
      */
     public String sendEnvelopeWithStatus(String content) {
         try {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 3190fb0..17db1b4 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -707,8 +707,8 @@
      * @hide
      */
     @Override
-    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
-            int userIdDest) {
+    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
+            int sourceUserId, int targetUserId) {
         throw new UnsupportedOperationException();
     }
 
@@ -716,7 +716,24 @@
      * @hide
      */
     @Override
-    public void clearForwardingIntentFilters(int userIdOrig) {
+    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int sourceUserId,
+            int targetUserId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearCrossProfileIntentFilters(int sourceUserId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearForwardingIntentFilters(int sourceUserId) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java
index fa0f995..6876f5a 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java
@@ -26,6 +26,7 @@
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
 import android.os.Handler;
 import android.renderscript.Allocation;
 import android.renderscript.Element;
@@ -86,7 +87,7 @@
 
         @Override
         public void onCaptureCompleted(CameraDevice camera, CaptureRequest request,
-                CaptureResult result) {
+                TotalCaptureResult result) {
             // TODO Auto-generated method stub
             Log.v(TAG, "in onCaptureComplete");
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 118f258..d0f2a2d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -24,12 +24,13 @@
         android:viewportHeight="480"
         android:viewportWidth="480" />
 
-    <path
-        android:name="box1"
-        android:fill="?android:attr/colorControlActivated"
-        android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
-        android:stroke="?android:attr/colorControlActivated"
-        android:strokeLineCap="round"
-        android:strokeLineJoin="round" />
-
-</vector>
\ No newline at end of file
+    <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:strokeLineCap="round"
+            android:strokeLineJoin="round" />
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
index 034f7a0..40f23f0 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
@@ -1,5 +1,4 @@
-<!--
- 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.
@@ -16,23 +15,22 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-        android:height="64dp"
-        android:width="64dp" />
+        android:width="64dp"
+        android:height="64dp"/>
 
-    <viewport
-        android:viewportHeight="320"
-        android:viewportWidth="320" />
-
-    <path
-        android:name="house"
-        android:fill="#ff440000"
-        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:pivotX="70"
-        android:pivotY="120"
+    <viewport android:viewportWidth="320"
+          android:viewportHeight="320"/>
+    <group
         android:rotation="180"
-        android:stroke="#FF00FF00"
-        android:strokeWidth="10"
-        android:trimPathEnd=".9"
-        android:trimPathStart=".1" />
-
-</vector>
\ No newline at end of file
+        android:pivotX="70"
+        android:pivotY="120">
+        <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:strokeWidth="10"
+            android:trimPathStart=".1"
+            android:trimPathEnd=".9"/>
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
index 451b28e..5b4c4ab 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
@@ -23,40 +23,47 @@
         android:viewportHeight="12.25"
         android:viewportWidth="7.30625" />
 
-    <path
-        android:name="clip1"
-        android:clipToPath="true"
-        android:pathData="
-                M 0, 0
-                l 7.3, 0
-                l 0, 0
-                l -7.3, 0
-                z"
+    <group
         android:pivotX="3.65"
         android:pivotY="6.125"
-        android:rotation="-30" />
-    <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" />
-    <path
-        android:name="clip2"
-        android:clipToPath="true"
-        android:pathData="
-                M 0, 0
+        android:rotation="-30" >
+        <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
-                z"
+                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" />
+    </group>
+    <group
         android:pivotX="3.65"
         android:pivotY="6.125"
-        android:rotation="-30" />
-    <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
+        android:rotation="-30" >
+        <path
+            android:name="clip2"
+            android:clipToPath="true"
+            android:pathData="
+                M 0, 0
+                l 7.3, 0
+                l 0, 6.125
+                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
@@ -65,5 +72,6 @@
                         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 6f9caa8..90694fb 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
@@ -1,5 +1,4 @@
-<!--
- 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.
@@ -13,44 +12,48 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+<vector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <size
-        android:height="64dp"
-        android:width="64dp" />
+            android:width="64dp"
+            android:height="64dp"/>
 
     <viewport
-        android:viewportHeight="12.25"
-        android:viewportWidth="7.30625" />
+            android:viewportWidth="7.30625"
+            android:viewportHeight="12.25"/>
 
-    <path
-        android:name="clip1"
-        android:clipToPath="true"
-        android:fill="#112233"
-        android:pathData="
+    <group>
+        <path
+                android:name="clip1"
+                android:pathData="
                 M 3.65, 6.125
                 m -.001, 0
                 a .001,.001 0 1,0 .002,0
-                a .001,.001 0 1,0 -.002,0z" />
-    <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
+                a .001,.001 0 1,0 -.002,0z"
+                android:clipToPath="true"
+                android:fill="#112233"
+                />
+
+        <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" />
-    <path
-        android:name="clip2"
-        android:clipToPath="true"
-        android:fill="#112233"
-        android:pathData="
+                l -5.046875,0.0 0.0,-1.0Z"
+                android:fill="#ff88ff"
+                />
+        <path
+                android:name="clip2"
+                android:pathData="
                 M 3.65, 6.125
                 m -6, 0
                 a 6,6 0 1,0 12,0
-                a 6,6 0 1,0 -12,0z" />
-    <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
+                a 6,6 0 1,0 -12,0z"
+                android:clipToPath="true"
+                android:fill="#112233"
+                />
+        <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
@@ -58,6 +61,8 @@
                         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" />
-
-</vector>
\ No newline at end of file
+                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
+                android:fill="#ff88ff"
+                />
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index e6c2557..c6595fa 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -23,17 +23,18 @@
         android:viewportHeight="12.25"
         android:viewportWidth="7.30625" />
 
-    <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
+    <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" />
-    <path
-        android:name="two"
-        android:fill="#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
+        <path
+            android:name="two"
+            android:fill="#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
@@ -42,5 +43,5 @@
                         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 3f8cc09..850de28 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
@@ -1,5 +1,4 @@
-<!--
- 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.
@@ -16,38 +15,34 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-        android:height="64dp"
-        android:width="64dp" />
+            android:width="64dp"
+            android:height="64dp"/>
 
     <viewport
-        android:viewportHeight="700"
-        android:viewportWidth="700" />
+            android:viewportWidth="700"
+            android:viewportHeight="700"/>
 
-    <path
-        android:name="path2451"
-        android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
-        android:stroke="#FF000000"
-        android:strokeWidth="30.65500000000000" />
-    <path
-        android:name="path2453"
-        android:pathData="M 365.015 311.066"
-        android:stroke="#FF000000"
-        android:strokeWidth="30.655000000000001" />
-    <path
-        android:name="path2455"
-        android:fill="#FFFFFFFF"
-        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:stroke="#FF000000"
-        android:strokeWidth="30.655000000000001" />
-    <path
-        android:name="path2457"
-        android:pathData="M 170.515 451.566L 305.61 313.46"
-        android:stroke="#000000"
-        android:strokeWidth="30.655000000000001" />
-    <path
-        android:name="path2459"
-        android:pathData="M 557.968 449.974L 426.515 315.375"
-        android:stroke="#000000"
-        android:strokeWidth="30.655000000000001" />
-
-</vector>
\ No newline at end of file
+    <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:stroke="#FF000000"
+              android:strokeWidth="30.65500000000000"/>
+        <path android:pathData="M 365.015 311.066"
+              android:name="path2453"
+              android:stroke="#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:strokeWidth="30.655000000000001"/>
+        <path android:pathData="M 170.515 451.566L 305.61 313.46"
+              android:name="path2457"
+              android:stroke="#000000"
+              android:strokeWidth="30.655000000000001"/>
+        <path android:pathData="M 557.968 449.974L 426.515 315.375"
+              android:name="path2459"
+              android:stroke="#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 4db5090..7c7e679 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
@@ -1,5 +1,4 @@
-<!--
- 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.
@@ -13,21 +12,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" >
-
+<vector xmlns:android="http://schemas.android.com/apk/res/android"   >
     <size
-        android:height="64dp"
-        android:width="64dp" />
+            android:width="64dp"
+            android:height="64dp"/>
 
-    <viewport
-        android:viewportHeight="110"
-        android:viewportWidth="140" />
+    <viewport android:viewportWidth="140"
+          android:viewportHeight="110"/>
 
-    <path
-        android:name="back"
-        android:fill="#ffffffff"
-        android:pathData="M 20,55 l 35.3,-35.3 7.07,7.07 -35.3,35.3 z
+    <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" />
-
-</vector>
\ No newline at end of file
+              M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z"
+                android:fill="#ffffffff"
+                />
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
index 44ef979..59f7459 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
@@ -1,5 +1,4 @@
-<!--
- 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.
@@ -16,18 +15,20 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-        android:height="64dp"
-        android:width="64dp" />
+            android:width="64dp"
+            android:height="64dp"/>
 
-    <viewport
-        android:viewportHeight="600"
-        android:viewportWidth="600" />
 
-    <path
-        android:name="pie1"
-        android:fill="#ffffcc00"
-        android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
-        android:stroke="#FF00FF00"
-        android:strokeWidth="1" />
+    <viewport android:viewportWidth="600"
+          android:viewportHeight="600"/>
 
-</vector>
\ No newline at end of file
+    <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:strokeWidth="1"/>
+    </group>
+
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index 248a143..c93c85f 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -23,12 +23,14 @@
         android:viewportHeight="200"
         android:viewportWidth="200" />
 
-    <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"
+    <group
         android:pivotX="100"
         android:pivotY="100"
-        android:rotation="90" />
+        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"/>
+    </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 56c2972..8484e9e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -21,24 +21,26 @@
         android:width="64dp" />
 
     <viewport
-        android:viewportHeight="200"
-        android:viewportWidth="200" />
+        android:viewportWidth="200"
+        android:viewportHeight="200"/>
 
-    <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" />
-    <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" />
-    <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" />
-    <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" />
+    <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" />
+        <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" />
+        <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" />
+        <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" />
+    </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 16d8b48..3422bbf 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -23,16 +23,17 @@
         android:viewportHeight="80"
         android:viewportWidth="40" />
 
-    <path
-        android:name="battery"
-        android:fill="#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:rotation="0"
-        android:stroke="#ff8833"
-        android:strokeWidth="1" />
-    <path
-        android:name="spark"
-        android:fill="#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>
+        <path
+            android:name="battery"
+            android:fill="#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:strokeWidth="1" />
+        <path
+            android:name="spark"
+            android:fill="#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>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 0a0407d..d0edd8c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -23,20 +23,19 @@
         android:viewportHeight="600"
         android:viewportWidth="600" />
 
-    <path
-        android:name="pie1"
-        android:pathData="M300,70 a230,230 0 1,0 1,0 z"
-        android:stroke="#FF00FF00"
-        android:strokeWidth="70"
-        android:trimPathEnd=".75"
-        android:trimPathOffset="0"
-        android:trimPathStart="0" />
-    <path
-        android:name="v"
-        android:fill="#FF00FF00"
-        android:pathData="M300,70 l 0,-70 70,70 -70,70z"
-        android:pivotX="300"
-        android:pivotY="300"
-        android:rotation="0" />
+    <group>
+        <path
+            android:name="pie1"
+            android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+            android:stroke="#FF00FF00"
+            android:strokeWidth="70"
+            android:trimPathEnd=".75"
+            android:trimPathOffset="0"
+            android:trimPathStart="0" />
+        <path
+            android:name="v"
+            android:fill="#FF00FF00"
+            android:pathData="M300,70 l 0,-70 70,70 -70,70z"/>
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index 385b1e9..8c946df 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -23,20 +23,19 @@
         android:viewportHeight="400"
         android:viewportWidth="600" />
 
-    <path
-        android:name="pie1"
-        android:fill="#ffffffff"
-        android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
-        android:stroke="#FF00FF00"
-        android:strokeWidth="1" />
-    <path
-        android:name="half"
-        android:fill="#FFFF0000"
-        android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
-        android:pivotX="300"
-        android:pivotY="200"
-        android:rotation="0"
-        android:stroke="#FF0000FF"
-        android:strokeWidth="5" />
+    <group>
+        <path
+            android:name="pie1"
+            android:fill="#ffffffff"
+            android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+            android:stroke="#FF00FF00"
+            android:strokeWidth="1" />
+        <path
+            android:name="half"
+            android:fill="#FFFF0000"
+            android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+            android:stroke="#FF0000FF"
+            android:strokeWidth="5" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index b701b35..1abe1e1 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -23,17 +23,19 @@
         android:viewportHeight="500"
         android:viewportWidth="800" />
 
-    <path
-        android:name="pie2"
-        android:pathData="M200,350 l 50,-25
+    <group
+        android:pivotX="90"
+        android:pivotY="100"
+        android:rotation="20">
+        <path
+            android:name="pie2"
+            android:pathData="M200,350 l 50,-25
            a25,12 -30 0,1 100,-50 l 50,-25
            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:pivotX="90"
-        android:pivotY="100"
-        android:rotation="20"
-        android:stroke="#FF00FF00"
-        android:strokeWidth="10" />
+            android:stroke="#FF00FF00"
+            android:strokeWidth="10" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index 8d773e1..b08e157 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -23,14 +23,16 @@
         android:viewportHeight="400"
         android:viewportWidth="500" />
 
-    <path
-        android:name="house"
-        android:fill="#ff440000"
-        android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+    <group
         android:pivotX="250"
         android:pivotY="200"
-        android:rotation="180"
-        android:stroke="#FFFF0000"
-        android:strokeWidth="10" />
+        android:rotation="180">
+        <path
+            android:name="house"
+            android:fill="#ff440000"
+            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+            android:stroke="#FFFF0000"
+            android:strokeWidth="10" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index 3b7926c..bbff833 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -23,13 +23,12 @@
         android:viewportHeight="200"
         android:viewportWidth="200" />
 
-    <path
-        android:name="house"
-        android:pathData="M 100,10 v 90 M 10,100 h 90"
-        android:pivotX="100"
-        android:pivotY="100"
-        android:rotation="360"
-        android:stroke="#FF00FF00"
-        android:strokeWidth="10" />
+    <group>
+        <path
+            android:name="house"
+            android:pathData="M 100,10 v 90 M 10,100 h 90"
+            android:stroke="#FF00FF00"
+            android:strokeWidth="10" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
index 1ec72be..8e98d02 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
@@ -1,5 +1,4 @@
-<!--
- 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.
@@ -16,20 +15,18 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-        android:height="64dp"
-        android:width="64dp" />
+            android:width="64dp"
+            android:height="64dp"/>
 
-    <viewport
-        android:viewportHeight="600"
-        android:viewportWidth="1200" />
+    <viewport android:viewportWidth="1200"
+          android:viewportHeight="600"/>
 
-    <path
-        android:name="house"
-        android:pathData="M200,300 Q400,50 600,300 T1000,300"
-        android:pivotX="600"
-        android:pivotY="300"
-        android:rotation="360"
-        android:stroke="#FFFF0000"
-        android:strokeWidth="10" />
+    <group>
+        <path
+                android:name="house"
+                android:pathData="M200,300 Q400,50 600,300 T1000,300"
+                android:stroke="#FFFF0000"
+                android:strokeWidth="10"/>
+    </group>
 
-</vector>
\ No newline at end of file
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index 12d0e93..6d74ebd 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -23,13 +23,12 @@
         android:viewportHeight="400"
         android:viewportWidth="500" />
 
-    <path
-        android:name="house"
-        android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-        android:pivotX="250"
-        android:pivotY="200"
-        android:rotation="360"
-        android:stroke="#FFFFFF00"
-        android:strokeWidth="10" />
+    <group>
+        <path
+            android:name="house"
+            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+            android:stroke="#FFFFFF00"
+            android:strokeWidth="10" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index 017e04c..a890fd6 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -23,12 +23,14 @@
         android:viewportHeight="800"
         android:viewportWidth="1000" />
 
-    <path
-        android:name="house"
-        android:pathData="M10,300 Q400,550 600,300 T1000,300"
-        android:pivotX="90"
-        android:pivotY="100"
-        android:stroke="#FFFF0000"
-        android:strokeWidth="60" />
+    <group>
+        <path
+            android:name="house"
+            android:pathData="M10,300 Q400,550 600,300 T1000,300"
+            android:pivotX="90"
+            android:pivotY="100"
+            android:stroke="#FFFF0000"
+            android:strokeWidth="60" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
index b7002a3..b8af7e2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
@@ -23,14 +23,16 @@
         android:viewportHeight="480"
         android:viewportWidth="480" />
 
-    <path
-        android:name="edit"
-        android:fill="#FF00FFFF"
-        android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+    <group>
+        <path
+            android:name="edit"
+            android:fill="#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:strokeWidth="10" />
+            android:stroke="#FF000000"
+            android:strokeWidth="10" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
index cda213d..22ce795 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
@@ -23,8 +23,10 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <path
-        android:fill="#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>
+        <path
+            android:fill="#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>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
index 2cb6381..042173c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
@@ -23,8 +23,10 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <path
-        android:fill="#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>
+        <path
+            android:fill="#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>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
index d58942e..6b6f43d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
@@ -23,8 +23,10 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <path
-        android:fill="#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>
+        <path
+            android:fill="#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>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
index 4717be4..ba8ebca 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
@@ -23,11 +23,13 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <path
-        android:fillOpacity="0.9"
-        android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
-    <path
-        android:fillOpacity="0.9"
-        android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
+    <group>
+        <path
+            android:fillOpacity="0.9"
+            android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
+        <path
+            android:fillOpacity="0.9"
+            android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
index c626325..896a938 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
@@ -23,8 +23,10 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <path
-        android:fill="#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>
+        <path
+            android:fill="#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>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
index bad5a46..a9091ab 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
@@ -23,10 +23,12 @@
         android:viewportHeight="512"
         android:viewportWidth="512" />
 
-    <path
-        android:name="002b"
-        android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
-        android:stroke="#FF0000FF"
-        android:strokeWidth="4" />
+    <group>
+        <path
+            android:name="002b"
+            android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
+            android:stroke="#FF0000FF"
+            android:strokeWidth="4" />
+    </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 c92b6f4..ab58c06 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
@@ -23,10 +23,12 @@
         android:viewportHeight="512"
         android:viewportWidth="512" />
 
-    <path
-        android:name="002b"
-        android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
-        android:stroke="#FF0000FF"
-        android:strokeWidth="4" />
+    <group>
+        <path
+            android:name="002b"
+            android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
+            android:stroke="#FF0000FF"
+            android:strokeWidth="4" />
+    </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index b918cdd..dcc7769 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -68,7 +68,6 @@
         TextView t = new TextView(this);
         DecimalFormat df = new DecimalFormat("#.##");
         t.setText("avgL=" + df.format(time / (icon.length * 1000000.)) + " ms");
-        t.setBackgroundColor(0xFF000000);
         container.addView(t);
         time =  android.os.SystemClock.elapsedRealtimeNanos();
         for (int i = 0; i < icon.length; i++) {
@@ -81,7 +80,6 @@
         time =  android.os.SystemClock.elapsedRealtimeNanos()-time;
         t = new TextView(this);
         t.setText("avgS=" + df.format(time / (icon.length * 1000000.)) + " ms");
-        t.setBackgroundColor(0xFF000000);
         container.addView(t);
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
index 31d1594..f4a9f52 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -97,6 +97,13 @@
         return found;
     }
 
+    @LayoutlibDelegate
+    /*package*/ static TypedArray resolveAttributes(Resources thisResources, Theme thisTheme,
+            int[] values, int[] attrs) {
+        // FIXME
+        return null;
+    }
+
     // ---- private helper methods ----
 
     private static boolean setupResources(Theme thisTheme) {
diff --git a/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java
index 0a7899a..5d89f83 100644
--- a/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java
@@ -27,4 +27,10 @@
         // pass
         return false;
     }
+
+    @LayoutlibDelegate
+    /*package*/ static TypedArray obtain(Resources res, int len) {
+        // FIXME
+        return null;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
index 802cf1c..33813d1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -18,9 +18,11 @@
 
 import java.awt.Font;
 import java.awt.Graphics2D;
+import java.awt.Toolkit;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -36,12 +38,12 @@
 @SuppressWarnings("deprecation")
 public class BidiRenderer {
 
-    /* package */ static class ScriptRun {
+    /*package*/ static class ScriptRun {
         int start;
         int limit;
         boolean isRtl;
         int scriptCode;
-        FontInfo font;
+        Font font;
 
         public ScriptRun(int start, int limit, boolean isRtl) {
             this.start = start;
@@ -51,9 +53,10 @@
         }
     }
 
-    private Graphics2D mGraphics;
-    private Paint_Delegate mPaint;
+    private final Graphics2D mGraphics;
+    private final Paint_Delegate mPaint;
     private char[] mText;
+    private List<Font> mFonts;
     // Bounds of the text drawn so far.
     private RectF mBounds;
     private float mBaseline;
@@ -63,11 +66,15 @@
      * @param paint The Paint to use to get the fonts. Should not be null.
      * @param text Unidirectional text. Should not be null.
      */
-    /* package */ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
+    /*package*/ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
         assert (paint != null);
         mGraphics = graphics;
         mPaint = paint;
         mText = text;
+        mFonts = new ArrayList<Font>(paint.getFonts().size());
+        for (FontInfo fontInfo : paint.getFonts()) {
+            mFonts.add(fontInfo.mFont);
+        }
     }
 
     /**
@@ -94,7 +101,7 @@
         // the script runs.
         mBounds = new RectF(x, y, x, y);
         mBaseline = y;
-        for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mPaint.getFonts())) {
+        for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mFonts)) {
             int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
             flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
             renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw);
@@ -108,16 +115,15 @@
      * much as possible. This also implements a fallback mechanism to render characters that cannot
      * be drawn using the preferred font.
      */
-    private void renderScript(int start, int limit, FontInfo preferredFont, int flag,
+    private void renderScript(int start, int limit, Font preferredFont, int flag,
             float[] advances, int advancesIndex, boolean draw) {
-        List<FontInfo> fonts = mPaint.getFonts();
-        if (fonts == null || preferredFont == null) {
+        if (mFonts.size() == 0 || preferredFont == null) {
             return;
         }
 
         while (start < limit) {
             boolean foundFont = false;
-            int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(mText, start, limit);
+            int canDisplayUpTo = preferredFont.canDisplayUpTo(mText, start, limit);
             if (canDisplayUpTo == -1) {
                 // We can draw all characters in the text.
                 render(start, limit, preferredFont, flag, advances, advancesIndex, draw);
@@ -133,8 +139,8 @@
             // The current character cannot be drawn with the preferred font. Cycle through all the
             // fonts to check which one can draw it.
             int charCount = Character.isHighSurrogate(mText[start]) ? 2 : 1;
-            for (FontInfo font : fonts) {
-                canDisplayUpTo = font.mFont.canDisplayUpTo(mText, start, start + charCount);
+            for (Font font : mFonts) {
+                canDisplayUpTo = font.canDisplayUpTo(mText, start, start + charCount);
                 if (canDisplayUpTo == -1) {
                     render(start, start+charCount, font, flag, advances, advancesIndex, draw);
                     start += charCount;
@@ -160,15 +166,19 @@
      * Renders the text to the right of the bounds with the given font.
      * @param font The font to render the text with.
      */
-    private void render(int start, int limit, FontInfo font, int flag, float[] advances,
+    private void render(int start, int limit, Font font, int flag, float[] advances,
             int advancesIndex, boolean draw) {
 
-        // Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with
-        // the anti-aliasing set.
-        FontRenderContext f = font.mMetrics.getFontRenderContext();
-        FontRenderContext frc = new FontRenderContext(f.getTransform(), mPaint.isAntiAliased(),
-                f.usesFractionalMetrics());
-        GlyphVector gv = font.mFont.layoutGlyphVector(frc, mText, start, limit, flag);
+        FontRenderContext frc;
+        if (mGraphics != null) {
+            frc = mGraphics.getFontRenderContext();
+        } else {
+            frc = Toolkit.getDefaultToolkit().getFontMetrics(font).getFontRenderContext();
+            // Metrics obtained this way don't have anti-aliasing set. So,
+            // we create a new FontRenderContext with anti-aliasing set.
+            frc = new FontRenderContext(font.getTransform(), mPaint.isAntiAliased(), frc.usesFractionalMetrics());
+        }
+        GlyphVector gv = font.layoutGlyphVector(frc, mText, start, limit, flag);
         int ng = gv.getNumGlyphs();
         int[] ci = gv.getGlyphCharIndices(0, ng, null);
         if (advances != null) {
@@ -206,7 +216,7 @@
     }
 
     /* package */  static List<ScriptRun> getScriptRuns(char[] text, int start, int limit,
-            boolean isRtl, List<FontInfo> fonts) {
+            boolean isRtl, List<Font> fonts) {
         LinkedList<ScriptRun> scriptRuns = new LinkedList<ScriptRun>();
 
         int count = limit - start;
@@ -225,10 +235,10 @@
 
     // TODO: Replace this method with one which returns the font based on the scriptCode.
     private static void setScriptFont(char[] text, ScriptRun run,
-            List<FontInfo> fonts) {
-        for (FontInfo fontInfo : fonts) {
-            if (fontInfo.mFont.canDisplayUpTo(text, run.start, run.limit) == -1) {
-                run.font = fontInfo;
+            List<Font> fonts) {
+        for (Font font : fonts) {
+            if (font.canDisplayUpTo(text, run.start, run.limit) == -1) {
+                run.font = font;
                 return;
             }
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 56c0de9..e9daffd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -979,7 +979,6 @@
             final float startX, final float startY, final int flags, long paint,
             long typeface) {
 
-        // TODO: use typeface.
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
             @Override
@@ -1097,7 +1096,7 @@
     /**
      * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.
      * <p>Note that the drawable may actually be executed several times if there are
-     * layers involved (see {@link #saveLayer(RectF, int, int)}.
+     * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}.
      */
     private static void draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode,
             GcSnapshot.Drawable drawable) {
@@ -1117,7 +1116,7 @@
      * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided
      * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
      * <p>Note that the drawable may actually be executed several times if there are
-     * layers involved (see {@link #saveLayer(RectF, int, int)}.
+     * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}.
      */
     private static void draw(long nCanvas, GcSnapshot.Drawable drawable) {
         // get the delegate from the native int.
@@ -1190,12 +1189,6 @@
         return mSnapshot.clipRect(left, top, right, bottom, regionOp);
     }
 
-    private void setBitmap(Bitmap_Delegate bitmap) {
-        mBitmap = bitmap;
-        assert mSnapshot.size() == 1;
-        mSnapshot.setBitmap(mBitmap);
-    }
-
     private static void drawBitmap(
             long nativeCanvas,
             Bitmap_Delegate bitmap,
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
new file mode 100644
index 0000000..5e7543a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -0,0 +1,225 @@
+/*
+ * 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.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Font;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.graphics.Typeface_Delegate.SYSTEM_FONTS;
+
+/**
+ * Delegate implementing the native methods of android.graphics.FontFamily
+ *
+ * Through the layoutlib_create tool, the original native methods of FontFamily have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original FontFamily class.
+ *
+ * @see DelegateManager
+ */
+public class FontFamily_Delegate {
+
+    // FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked
+    // separately.
+    private static final String FONT_SUFFIX_BOLDITALIC = "BoldItalic.ttf";
+    private static final String FONT_SUFFIX_BOLD = "Bold.ttf";
+    private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
+    private static final String FONT_SUBSTRING_COMPACT = "UI";
+
+    /**
+     * A class associating {@link Font} with its metadata.
+     */
+    private static final class FontInfo {
+        Font mFont;
+        /** Regular, Bold, Italic, or BoldItalic. */
+        int mStyle;
+        /**
+         * The variant of the Font - compact or elegant.
+         * @see Paint#setElegantTextHeight(boolean)
+         */
+        boolean mIsCompact;
+    }
+
+    // ---- delegate manager ----
+    private static final DelegateManager<FontFamily_Delegate> sManager =
+            new DelegateManager<FontFamily_Delegate>(FontFamily_Delegate.class);
+
+    // ---- delegate helper data ----
+    private static String sFontLocation;
+    private static final List<FontFamily_Delegate> sPostInitDelegate = new
+            ArrayList<FontFamily_Delegate>();
+
+
+    // ---- delegate data ----
+    private List<FontInfo> mFonts = new ArrayList<FontInfo>();
+    // Path of fonts that haven't been created since sFontLoader hasn't been initialized.
+    private List<String> mPath = new ArrayList<String>();
+
+
+    // ---- Public Helper methods ----
+
+    public static FontFamily_Delegate getDelegate(long nativeFontFamily) {
+        return sManager.getDelegate(nativeFontFamily);
+    }
+
+    public static synchronized void setFontLocation(String fontLocation) {
+        sFontLocation = fontLocation;
+        for (FontFamily_Delegate fontFamily : sPostInitDelegate) {
+            fontFamily.init();
+        }
+        sPostInitDelegate.clear();
+    }
+
+    public Font getFont(int style, boolean isCompact) {
+        FontInfo plainFont = null;
+        FontInfo styledFont = null;  // Font matching the style but not isCompact
+        for (FontInfo font : mFonts) {
+            if (font.mStyle == style) {
+                if (font.mIsCompact == isCompact) {
+                    return font.mFont;
+                }
+                styledFont = font;
+            }
+            if (font.mStyle == Font.PLAIN) {
+                if (plainFont == null) {
+                    plainFont = font;
+                    continue;
+                }
+                if (font.mIsCompact == isCompact) {
+                    // Override the previous selection of plain font since we've found a better one.
+                    plainFont = font;
+                }
+            }
+        }
+        if (styledFont != null) {
+            return styledFont.mFont;
+        }
+
+        // No font with the mentioned style is found. Try to derive one.
+        if (plainFont != null && style > 0 && style < 4) {
+            styledFont = new FontInfo();
+            styledFont.mFont = plainFont.mFont.deriveFont(style);
+            styledFont.mStyle = style;
+            styledFont.mIsCompact = plainFont.mIsCompact;
+            // Add the font to the list of fonts so that we don't have to derive it the next time.
+            mFonts.add(styledFont);
+            return styledFont.mFont;
+        }
+        return null;
+    }
+
+    // ---- native methods ----
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreateFamily() {
+        FontFamily_Delegate delegate = new FontFamily_Delegate();
+        if (sFontLocation != null) {
+            delegate.init();
+        } else {
+            sPostInitDelegate.add(delegate);
+        }
+        return sManager.addNewDelegate(delegate);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nUnrefFamily(long nativePtr) {
+        sManager.removeJavaReferenceFor(nativePtr);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nAddFont(long nativeFamily, String path) {
+        FontFamily_Delegate delegate = getDelegate(nativeFamily);
+        if (delegate != null) {
+            if (sFontLocation == null) {
+                delegate.mPath.add(path);
+                return true;
+            }
+            return delegate.addFont(path);
+        }
+        return false;
+    }
+
+    private void init() {
+        for (String path : mPath) {
+            addFont(path);
+        }
+        mPath = null;
+    }
+
+    private boolean addFont(String path) {
+        Font font = loadFont(path);
+        if (font == null) {
+            return false;
+        }
+        FontInfo fontInfo = new FontInfo();
+        fontInfo.mFont = font;
+        addFontMetadata(fontInfo, path);
+        // TODO ensure that mFonts doesn't have the font with this style already.
+        mFonts.add(fontInfo);
+        return true;
+    }
+
+    private static void addFontMetadata(FontInfo fontInfo, String path) {
+        int style = Font.PLAIN;
+        String fontName = path.substring(path.lastIndexOf('/'), path.length());
+        if (fontName.endsWith(FONT_SUFFIX_BOLDITALIC)) {
+            style = Font.BOLD | Font.ITALIC;
+        } else if (fontName.endsWith(FONT_SUFFIX_BOLD)) {
+            style = Font.BOLD;
+        } else if (fontName.endsWith(FONT_SUFFIX_ITALIC)) {
+            style = Font.ITALIC;
+        }
+        fontInfo.mStyle = style;
+
+        // Names of compact fonts end with UI-<style>.ttf. For example, NotoNakshUI-Regular.ttf.
+        // This should go away when this info is passed on by nAddFont().
+        int hyphenIndex = fontName.lastIndexOf('-');
+        fontInfo.mIsCompact = hyphenIndex > 0 &&
+                fontName.substring(0, hyphenIndex).endsWith(FONT_SUBSTRING_COMPACT);
+
+    }
+
+    private static Font loadFont(String path) {
+        if (path.startsWith(SYSTEM_FONTS) ) {
+            String relativePath = path.substring(SYSTEM_FONTS.length());
+            File f = new File(sFontLocation, relativePath);
+
+            try {
+                return Font.createFont(Font.TRUETYPE_FONT, f);
+            } catch (Exception e) {
+                Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
+                        String.format("Unable to load font %1$s", relativePath),
+                        null /*throwable*/, null /*data*/);
+            }
+        } else {
+            Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                    "Only platform fonts located in " + SYSTEM_FONTS + "can be loaded.",
+                    null /*throwable*/, null /*data*/);
+        }
+
+        return null;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 8862f5b..f42f48f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -203,6 +203,16 @@
     }
 
     @LayoutlibDelegate
+    /*package*/ static boolean native_isAffine(long native_object) {
+        Matrix_Delegate d = sManager.getDelegate(native_object);
+        if (d == null) {
+            return true;
+        }
+
+        return (d.computeTypeMask() & kPerspective_Mask) == 0;
+    }
+
+    @LayoutlibDelegate
     /*package*/ static boolean native_rectStaysRect(long native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 83df745..911f4e7 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -53,7 +53,7 @@
 public class Paint_Delegate {
 
     /**
-     * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
+     * Class associating a {@link Font} and its {@link java.awt.FontMetrics}.
      */
     /*package*/ static final class FontInfo {
         Font mFont;
@@ -66,8 +66,6 @@
 
     // ---- delegate helper data ----
     private List<FontInfo> mFonts;
-    private final FontRenderContext mFontContext = new FontRenderContext(
-            new AffineTransform(), true, true);
 
     // ---- delegate data ----
     private int mFlags;
@@ -83,6 +81,7 @@
     private float mTextScaleX;
     private float mTextSkewX;
     private int mHintingMode = Paint.HINTING_ON;
+    private boolean mIsCompact = true;
 
     private Xfermode_Delegate mXfermode;
     private ColorFilter_Delegate mColorFilter;
@@ -101,8 +100,7 @@
     }
 
     /**
-     * Returns the list of {@link Font} objects. The first item is the main font, the rest
-     * are fall backs for characters not present in the main font.
+     * Returns the list of {@link Font} objects.
      */
     public List<FontInfo> getFonts() {
         return mFonts;
@@ -437,12 +435,20 @@
 
     @LayoutlibDelegate
     /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
-        return false;
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        return delegate != null && !delegate.mIsCompact;
     }
 
     @LayoutlibDelegate
     /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
-        // TODO
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            return;
+        }
+
+        delegate.mIsCompact = !elegant;
     }
 
     @LayoutlibDelegate
@@ -621,7 +627,6 @@
         int inc = count > 0 ? 1 : -1;
 
         int measureIndex = 0;
-        float measureAcc = 0;
         for (int i = index; i != index + count; i += inc, measureIndex++) {
             int start, end;
             if (i < index) {
@@ -640,7 +645,6 @@
                 measuredWidth[measureIndex] = res;
             }
 
-            measureAcc += res;
             if (res > maxWidth) {
                 // we should not return this char index, but since it's 0-based
                 // and we need to return a count, we simply return measureIndex;
@@ -818,7 +822,7 @@
             return filter;
         }
 
-        delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);;
+        delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);
 
         // since none of those are supported, display a fidelity warning right away
         if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) {
@@ -940,52 +944,17 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_getTextWidths(long native_object, char[] text, int index,
-            int count, int bidiFlags, float[] widths) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return 0;
-        }
-
-        if (delegate.mFonts.size() > 0) {
-            // FIXME: handle multi-char characters (see measureText)
-            float totalAdvance = 0;
-            for (int i = 0; i < count; i++) {
-                char c = text[i + index];
-                boolean found = false;
-                for (FontInfo info : delegate.mFonts) {
-                    if (info.mFont.canDisplay(c)) {
-                        float adv = info.mMetrics.charWidth(c);
-                        totalAdvance += adv;
-                        if (widths != null) {
-                            widths[i] = adv;
-                        }
-
-                        found = true;
-                        break;
-                    }
-                }
-
-                if (found == false) {
-                    // no advance for this char.
-                    if (widths != null) {
-                        widths[i] = 0.f;
-                    }
-                }
-            }
-
-            return (int) totalAdvance;
-        }
-
-        return 0;
+    /*package*/ static int native_getTextWidths(long native_object, long native_typeface,
+            char[] text, int index, int count, int bidiFlags, float[] widths) {
+        return (int) native_getTextRunAdvances(native_object, native_typeface, text, index, count,
+                index, count, bidiFlags, widths, 0);
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_getTextWidths(long native_object, String text, int start,
-            int end, int bidiFlags, float[] widths) {
-        return native_getTextWidths(native_object, text.toCharArray(), start, end - start,
-                bidiFlags, widths);
+    /*package*/ static int native_getTextWidths(long native_object, long native_typeface,
+            String text, int start, int end, int bidiFlags, float[] widths) {
+        return native_getTextWidths(native_object, native_typeface, text.toCharArray(), start,
+                end - start, bidiFlags, widths);
     }
 
     @LayoutlibDelegate
@@ -997,15 +966,20 @@
 
     @LayoutlibDelegate
     /*package*/ static float native_getTextRunAdvances(long native_object,
+            long native_typeface /*ignored*/,
             char[] text, int index, int count, int contextIndex, int contextCount,
             int flags, float[] advances, int advancesIndex) {
 
+        // native_typeface is passed here since Framework's old implementation did not have the
+        // typeface object associated with the Paint. Since, we follow the new framework way,
+        // we store the typeface with the paint and use it directly.
+
         if (advances != null)
             for (int i = advancesIndex; i< advancesIndex+count; i++)
                 advances[i]=0;
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
+        if (delegate == null) {
             return 0.f;
         }
         boolean isRtl = isRtl(flags);
@@ -1017,7 +991,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static float native_getTextRunAdvances(long native_object,
+    /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
             String text, int start, int end, int contextStart, int contextEnd,
             int flags, float[] advances, int advancesIndex) {
         // FIXME: support contextStart and contextEnd
@@ -1025,8 +999,8 @@
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
 
-        return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
-                contextEnd - contextStart, flags, advances, advancesIndex);
+        return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count,
+                contextStart, contextEnd - contextStart, flags, advances, advancesIndex);
     }
 
     @LayoutlibDelegate
@@ -1076,7 +1050,7 @@
 
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
+        if (delegate == null) {
             return;
         }
         delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds);
@@ -1150,7 +1124,7 @@
     private void updateFontObject() {
         if (mTypeface != null) {
             // Get the fonts from the TypeFace object.
-            List<Font> fonts = mTypeface.getFonts();
+            List<Font> fonts = mTypeface.getFonts(mIsCompact);
 
             // create new font objects as well as FontMetrics, based on the current text size
             // and skew info.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 60cd157..ed8f3b4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -19,7 +19,6 @@
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.layoutlib.bridge.impl.FontLoader;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.content.res.AssetManager;
@@ -44,100 +43,67 @@
  */
 public final class Typeface_Delegate {
 
-    private static final String SYSTEM_FONTS = "/system/fonts/";
+    public static final String SYSTEM_FONTS = "/system/fonts/";
 
     // ---- delegate manager ----
     private static final DelegateManager<Typeface_Delegate> sManager =
             new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class);
 
     // ---- delegate helper data ----
-    private static final String DEFAULT_FAMILY = "sans-serif";
-
-    private static FontLoader sFontLoader;
-    private static final List<Typeface_Delegate> sPostInitDelegate =
-            new ArrayList<Typeface_Delegate>();
+    private static String sFontLocation;
 
     // ---- delegate data ----
 
-    private final String mFamily;
+    private final long[] mFontFamilies;  // the reference to FontFamily_Delegate.
     private int mStyle;
-    private List<Font> mFonts;
 
+    private static long sDefaultTypeface;
 
     // ---- Public Helper methods ----
-
-    public static synchronized void init(FontLoader fontLoader) {
-        sFontLoader = fontLoader;
-
-        for (Typeface_Delegate delegate : sPostInitDelegate) {
-            delegate.init();
-        }
-        sPostInitDelegate.clear();
+    public static synchronized void setFontLocation(String fontLocation) {
+        sFontLocation = fontLocation;
+        FontFamily_Delegate.setFontLocation(fontLocation);
     }
 
     public static Typeface_Delegate getDelegate(long nativeTypeface) {
         return sManager.getDelegate(nativeTypeface);
     }
 
-    public static List<Font> getFonts(Typeface typeface) {
-        return getFonts(typeface.native_instance);
-    }
-
-    public static List<Font> getFonts(long native_int) {
-        Typeface_Delegate delegate = sManager.getDelegate(native_int);
-        if (delegate == null) {
-            return null;
+    public List<Font> getFonts(boolean compact) {
+        List<Font> fonts = new ArrayList<Font>(mFontFamilies.length);
+        for (long fontFamily : mFontFamilies) {
+            FontFamily_Delegate ffd = FontFamily_Delegate.getDelegate(fontFamily);
+            if (ffd != null) {
+                Font font = ffd.getFont(mStyle, compact);
+                if (font != null) {
+                    fonts.add(font);
+                }
+            }
         }
-
-        return delegate.getFonts();
-    }
-
-    public List<Font> getFonts() {
-        return mFonts;
+        return fonts;
     }
 
     // ---- native methods ----
 
     @LayoutlibDelegate
     /*package*/ static synchronized long nativeCreate(String familyName, int style) {
-        if (familyName == null) {
-            familyName = DEFAULT_FAMILY;
-        }
-        if (style < 0) {
-            style = Typeface.NORMAL;
-        }
-
-        Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style);
-        if (sFontLoader != null) {
-            newDelegate.init();
-        } else {
-            // font loader has not been initialized yet, add the delegate to a list of delegates
-            // to init when the font loader is initialized.
-            // There won't be any rendering before this happens anyway.
-            sPostInitDelegate.add(newDelegate);
-        }
-
-        return sManager.addNewDelegate(newDelegate);
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                "Could not find font with family \"" + familyName + "\".",
+                null /*throwable*/, null /*data*/);
+        return 0;
     }
 
     @LayoutlibDelegate
     /*package*/ static synchronized long nativeCreateFromTypeface(long native_instance, int style) {
         Typeface_Delegate delegate = sManager.getDelegate(native_instance);
         if (delegate == null) {
+            delegate = sManager.getDelegate(sDefaultTypeface);
+        }
+        if (delegate == null) {
             return 0;
         }
 
-        Typeface_Delegate newDelegate = new Typeface_Delegate(delegate.mFamily, style);
-        if (sFontLoader != null) {
-            newDelegate.init();
-        } else {
-            // font loader has not been initialized yet, add the delegate to a list of delegates
-            // to init when the font loader is initialized.
-            // There won't be any rendering before this happens anyway.
-            sPostInitDelegate.add(newDelegate);
-        }
-
-        return sManager.addNewDelegate(newDelegate);
+        return sManager.addNewDelegate(new Typeface_Delegate(delegate.mFontFamilies, style));
     }
 
     @LayoutlibDelegate
@@ -149,31 +115,15 @@
 
     @LayoutlibDelegate
     /*package*/ static synchronized long nativeCreateFromFile(String path) {
-        if (path.startsWith(SYSTEM_FONTS) ) {
-            String relativePath = path.substring(SYSTEM_FONTS.length());
-            File f = new File(sFontLoader.getOsFontsLocation(), relativePath);
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                "Typeface.createFromFile() is not supported.,", null, null);
+        return 0;
+    }
 
-            try {
-                Font font = Font.createFont(Font.TRUETYPE_FONT, f);
-                if (font != null) {
-                    Typeface_Delegate newDelegate = new Typeface_Delegate(font);
-                    return sManager.addNewDelegate(newDelegate);
-                }
-            } catch (Exception e) {
-                Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
-                        String.format("Unable to load font %1$s", relativePath),
-                            null /*throwable*/, null /*data*/);
-            }
-        } else {
-            Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                    "Typeface.createFromFile() can only work with platform fonts located in " +
-                        SYSTEM_FONTS,
-                    null /*throwable*/, null /*data*/);
-        }
-
-
-        // return a copy of the base font
-        return nativeCreate(null, 0);
+    @LayoutlibDelegate
+    /*package*/ static synchronized long nativeCreateFromArray(long[] familyArray) {
+        Typeface_Delegate delegate = new Typeface_Delegate(familyArray, Typeface.NORMAL);
+        return sManager.addNewDelegate(delegate);
     }
 
     @LayoutlibDelegate
@@ -191,24 +141,21 @@
         return delegate.mStyle;
     }
 
+    @LayoutlibDelegate
+    /*package*/ static void nativeSetDefault(long native_instance) {
+        sDefaultTypeface = native_instance;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static File getSystemFontConfigLocation() {
+        return new File(sFontLocation);
+    }
+
     // ---- Private delegate/helper methods ----
 
-    private Typeface_Delegate(String family, int style) {
-        mFamily = family;
+    private Typeface_Delegate(long[] fontFamilies, int style) {
+        mFontFamilies = fontFamilies;
         mStyle = style;
     }
 
-    private Typeface_Delegate(Font font) {
-        mFamily = font.getFamily();
-        mStyle = Typeface.NORMAL;
-
-        mFonts = sFontLoader.getFallbackFonts(mStyle);
-
-        // insert the font glyph first.
-        mFonts.add(0, font);
-    }
-
-    private void init() {
-        mFonts = sFontLoader.getFont(mFamily, mStyle);
-    }
 }
diff --git a/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java b/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java
new file mode 100644
index 0000000..a193330
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Delegate overriding some methods of android.util.Xml
+ *
+ * Through the layoutlib_create tool, the original methods of Xml have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ */
+public class Xml_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static XmlPullParser newPullParser() {
+        try {
+            KXmlParser parser = new KXmlParser();
+            // The prebuilt kxml2 library with the IDE doesn't support DOCECL.
+//            parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+            return parser;
+        } catch (XmlPullParserException e) {
+            throw new AssertionError();
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index fa8050f..ffab4de 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -26,7 +26,6 @@
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.Result.Status;
 import com.android.ide.common.rendering.api.SessionParams;
-import com.android.layoutlib.bridge.impl.FontLoader;
 import com.android.layoutlib.bridge.impl.RenderDrawable;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 import com.android.layoutlib.bridge.util.DynamicIdMap;
@@ -61,7 +60,7 @@
 /**
  * Main entry point of the LayoutLib Bridge.
  * <p/>To use this bridge, simply instantiate an object of type {@link Bridge} and call
- * {@link #createScene(SceneParams)}
+ * {@link #createSession(SessionParams)}
  */
 public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
 
@@ -147,8 +146,7 @@
             if (getClass() != obj.getClass()) return false;
 
             IntArray other = (IntArray) obj;
-            if (!Arrays.equals(mArray, other.mArray)) return false;
-            return true;
+            return Arrays.equals(mArray, other.mArray);
         }
     }
 
@@ -251,14 +249,7 @@
         }
 
         // load the fonts.
-        FontLoader fontLoader = FontLoader.create(fontLocation.getAbsolutePath());
-        if (fontLoader != null) {
-            Typeface_Delegate.init(fontLoader);
-        } else {
-            log.error(LayoutLog.TAG_BROKEN,
-                    "Failed create FontLoader in layout lib.", null);
-            return false;
-        }
+        Typeface_Delegate.setFontLocation(fontLocation.getAbsolutePath());
 
         // now parse com.android.internal.R (and only this one as android.R is a subset of
         // the internal version), and put the content in the maps.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
deleted file mode 100644
index cc7338a..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge.impl;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import android.graphics.Typeface;
-
-import java.awt.Font;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Provides {@link Font} object to the layout lib.
- * <p/>
- * The fonts are loaded from the SDK directory. Family/style mapping is done by parsing the
- * fonts.xml file located alongside the ttf files.
- */
-public final class FontLoader {
-    private static final String FONTS_SYSTEM = "system_fonts.xml";
-    private static final String FONTS_VENDOR = "vendor_fonts.xml";
-    private static final String FONTS_FALLBACK = "fallback_fonts.xml";
-
-    private static final String NODE_FAMILYSET = "familyset";
-    private static final String NODE_FAMILY = "family";
-    private static final String NODE_NAME = "name";
-    private static final String NODE_FILE = "file";
-
-    private static final String ATTRIBUTE_VARIANT = "variant";
-    private static final String ATTRIBUTE_VALUE_ELEGANT = "elegant";
-    private static final String FONT_SUFFIX_NONE = ".ttf";
-    private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf";
-    private static final String FONT_SUFFIX_BOLD = "-Bold.ttf";
-    // FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked
-    // separately.
-    private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
-    private static final String FONT_SUFFIX_BOLDITALIC = "-BoldItalic.ttf";
-
-    // This must match the values of Typeface styles so that we can use them for indices in this
-    // array.
-    private static final int[] AWT_STYLES = new int[] {
-        Font.PLAIN,
-        Font.BOLD,
-        Font.ITALIC,
-        Font.BOLD | Font.ITALIC
-    };
-    private static int[] DERIVE_BOLD_ITALIC = new int[] {
-        Typeface.ITALIC, Typeface.BOLD, Typeface.NORMAL
-    };
-    private static int[] DERIVE_ITALIC = new int[] { Typeface.NORMAL };
-    private static int[] DERIVE_BOLD = new int[] { Typeface.NORMAL };
-
-    private static final List<FontInfo> mMainFonts = new ArrayList<FontInfo>();
-    private static final List<FontInfo> mFallbackFonts = new ArrayList<FontInfo>();
-
-    private final String mOsFontsLocation;
-
-    public static FontLoader create(String fontOsLocation) {
-        try {
-            SAXParserFactory parserFactory = SAXParserFactory.newInstance();
-                parserFactory.setNamespaceAware(true);
-
-            // parse the system fonts
-            FontHandler handler = parseFontFile(parserFactory, fontOsLocation, FONTS_SYSTEM);
-            List<FontInfo> systemFonts = handler.getFontList();
-
-
-            // parse the fallback fonts
-            handler = parseFontFile(parserFactory, fontOsLocation, FONTS_FALLBACK);
-            List<FontInfo> fallbackFonts = handler.getFontList();
-
-            return new FontLoader(fontOsLocation, systemFonts, fallbackFonts);
-        } catch (ParserConfigurationException e) {
-            // return null below
-        } catch (SAXException e) {
-            // return null below
-        } catch (FileNotFoundException e) {
-            // return null below
-        } catch (IOException e) {
-            // return null below
-        }
-
-        return null;
-    }
-
-    private static FontHandler parseFontFile(SAXParserFactory parserFactory,
-            String fontOsLocation, String fontFileName)
-            throws ParserConfigurationException, SAXException, IOException, FileNotFoundException {
-
-        SAXParser parser = parserFactory.newSAXParser();
-        File f = new File(fontOsLocation, fontFileName);
-
-        FontHandler definitionParser = new FontHandler(
-                fontOsLocation + File.separator);
-        parser.parse(new FileInputStream(f), definitionParser);
-        return definitionParser;
-    }
-
-    private FontLoader(String fontOsLocation,
-            List<FontInfo> fontList, List<FontInfo> fallBackList) {
-        mOsFontsLocation = fontOsLocation;
-        mMainFonts.addAll(fontList);
-        mFallbackFonts.addAll(fallBackList);
-    }
-
-
-    public String getOsFontsLocation() {
-        return mOsFontsLocation;
-    }
-
-    /**
-     * Returns a {@link Font} object given a family name and a style value (constant in
-     * {@link Typeface}).
-     * @param family the family name
-     * @param style a 1-item array containing the requested style. Based on the font being read
-     *              the actual style may be different. The array contains the actual style after
-     *              the method returns.
-     * @return the font object or null if no match could be found.
-     */
-    public synchronized List<Font> getFont(String family, int style) {
-        List<Font> result = new ArrayList<Font>();
-
-        if (family == null) {
-            return result;
-        }
-
-
-        // get the font objects from the main list based on family.
-        for (FontInfo info : mMainFonts) {
-            if (info.families.contains(family)) {
-                result.add(info.font[style]);
-                break;
-            }
-        }
-
-        // add all the fallback fonts for the given style
-        for (FontInfo info : mFallbackFonts) {
-            result.add(info.font[style]);
-        }
-
-        return result;
-    }
-
-
-    public synchronized List<Font> getFallbackFonts(int style) {
-        List<Font> result = new ArrayList<Font>();
-        // add all the fallback fonts
-        for (FontInfo info : mFallbackFonts) {
-            result.add(info.font[style]);
-        }
-        return result;
-    }
-
-
-    private final static class FontInfo {
-        final Font[] font = new Font[4]; // Matches the 4 type-face styles.
-        final Set<String> families;
-
-        FontInfo() {
-            families = new HashSet<String>();
-        }
-    }
-
-    private final static class FontHandler extends DefaultHandler {
-        private final String mOsFontsLocation;
-
-        private FontInfo mFontInfo = null;
-        private final StringBuilder mBuilder = new StringBuilder();
-        private List<FontInfo> mFontList = new ArrayList<FontInfo>();
-        private boolean isCompactFont = true;
-
-        private FontHandler(String osFontsLocation) {
-            super();
-            mOsFontsLocation = osFontsLocation;
-        }
-
-        public List<FontInfo> getFontList() {
-            return mFontList;
-        }
-
-        /* (non-Javadoc)
-         * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
-         */
-        @Override
-        public void startElement(String uri, String localName, String name, Attributes attributes)
-                throws SAXException {
-            if (NODE_FAMILYSET.equals(localName)) {
-                mFontList = new ArrayList<FontInfo>();
-            } else if (NODE_FAMILY.equals(localName)) {
-                if (mFontList != null) {
-                    mFontInfo = null;
-                }
-            } else if (NODE_NAME.equals(localName)) {
-                if (mFontList != null && mFontInfo == null) {
-                    mFontInfo = new FontInfo();
-                }
-            } else if (NODE_FILE.equals(localName)) {
-                if (mFontList != null && mFontInfo == null) {
-                    mFontInfo = new FontInfo();
-                }
-                if (ATTRIBUTE_VALUE_ELEGANT.equals(attributes.getValue(ATTRIBUTE_VARIANT))) {
-                    isCompactFont = false;
-                } else {
-                    isCompactFont = true;
-                }
-            }
-
-            mBuilder.setLength(0);
-
-            super.startElement(uri, localName, name, attributes);
-        }
-
-        /* (non-Javadoc)
-         * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
-         */
-        @Override
-        public void characters(char[] ch, int start, int length) throws SAXException {
-            if (isCompactFont) {
-              mBuilder.append(ch, start, length);
-            }
-        }
-
-        /* (non-Javadoc)
-         * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
-         */
-        @Override
-        public void endElement(String uri, String localName, String name) throws SAXException {
-            if (NODE_FAMILY.equals(localName)) {
-                if (mFontInfo != null) {
-                    // if has a normal font file, add to the list
-                    if (mFontInfo.font[Typeface.NORMAL] != null) {
-                        mFontList.add(mFontInfo);
-
-                        // create missing font styles, order is important.
-                        if (mFontInfo.font[Typeface.BOLD_ITALIC] == null) {
-                            computeDerivedFont(Typeface.BOLD_ITALIC, DERIVE_BOLD_ITALIC);
-                        }
-                        if (mFontInfo.font[Typeface.ITALIC] == null) {
-                            computeDerivedFont(Typeface.ITALIC, DERIVE_ITALIC);
-                        }
-                        if (mFontInfo.font[Typeface.BOLD] == null) {
-                            computeDerivedFont(Typeface.BOLD, DERIVE_BOLD);
-                        }
-                    }
-
-                    mFontInfo = null;
-                }
-            } else if (NODE_NAME.equals(localName)) {
-                // handle a new name for an existing Font Info
-                if (mFontInfo != null) {
-                    String family = trimXmlWhitespaces(mBuilder.toString());
-                    mFontInfo.families.add(family);
-                }
-            } else if (NODE_FILE.equals(localName)) {
-                // handle a new file for an existing Font Info
-                if (isCompactFont && mFontInfo != null) {
-                    String fileName = trimXmlWhitespaces(mBuilder.toString());
-                    Font font = getFont(fileName);
-                    if (font != null) {
-                        if (fileName.endsWith(FONT_SUFFIX_REGULAR)) {
-                            mFontInfo.font[Typeface.NORMAL] = font;
-                        } else if (fileName.endsWith(FONT_SUFFIX_BOLD)) {
-                            mFontInfo.font[Typeface.BOLD] = font;
-                        } else if (fileName.endsWith(FONT_SUFFIX_BOLDITALIC)) {
-                            mFontInfo.font[Typeface.BOLD_ITALIC] = font;
-                        } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) {
-                            mFontInfo.font[Typeface.ITALIC] = font;
-                        } else if (fileName.endsWith(FONT_SUFFIX_NONE)) {
-                            mFontInfo.font[Typeface.NORMAL] = font;
-                        }
-                    }
-                }
-            }
-        }
-
-        private Font getFont(String fileName) {
-            try {
-                File file = new File(mOsFontsLocation, fileName);
-                if (file.exists()) {
-                    return Font.createFont(Font.TRUETYPE_FONT, file);
-                }
-            } catch (Exception e) {
-
-            }
-
-            return null;
-        }
-
-        private void computeDerivedFont( int toCompute, int[] basedOnList) {
-            for (int basedOn : basedOnList) {
-                if (mFontInfo.font[basedOn] != null) {
-                    mFontInfo.font[toCompute] =
-                        mFontInfo.font[basedOn].deriveFont(AWT_STYLES[toCompute]);
-                    return;
-                }
-            }
-
-            // we really shouldn't stop there. This means we don't have a NORMAL font...
-            assert false;
-        }
-
-        private String trimXmlWhitespaces(String value) {
-            if (value == null) {
-                return null;
-            }
-
-            // look for carriage return and replace all whitespace around it by just 1 space.
-            int index;
-
-            while ((index = value.indexOf('\n')) != -1) {
-                // look for whitespace on each side
-                int left = index - 1;
-                while (left >= 0) {
-                    if (Character.isWhitespace(value.charAt(left))) {
-                        left--;
-                    } else {
-                        break;
-                    }
-                }
-
-                int right = index + 1;
-                int count = value.length();
-                while (right < count) {
-                    if (Character.isWhitespace(value.charAt(right))) {
-                        right++;
-                    } else {
-                        break;
-                    }
-                }
-
-                // remove all between left and right (non inclusive) and replace by a single space.
-                String leftString = null;
-                if (left >= 0) {
-                    leftString = value.substring(0, left + 1);
-                }
-                String rightString = null;
-                if (right < count) {
-                    rightString = value.substring(right);
-                }
-
-                if (leftString != null) {
-                    value = leftString;
-                    if (rightString != null) {
-                        value += " " + rightString;
-                    }
-                } else {
-                    value = rightString != null ? rightString : "";
-                }
-            }
-
-            // now we un-escape the string
-            int length = value.length();
-            char[] buffer = value.toCharArray();
-
-            for (int i = 0 ; i < length ; i++) {
-                if (buffer[i] == '\\') {
-                    if (buffer[i+1] == 'n') {
-                        // replace the char with \n
-                        buffer[i+1] = '\n';
-                    }
-
-                    // offset the rest of the buffer since we go from 2 to 1 char
-                    System.arraycopy(buffer, i+1, buffer, i, length - i - 1);
-                    length--;
-                }
-            }
-
-            return new String(buffer, 0, length);
-        }
-
-    }
-}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index bb72a1e..1f7a28e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -125,15 +125,19 @@
         "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
         "android.content.res.Resources$Theme#obtainStyledAttributes",
         "android.content.res.Resources$Theme#resolveAttribute",
+        "android.content.res.Resources$Theme#resolveAttributes",
         "android.content.res.Resources#localeToLanguageTag",
         "android.content.res.AssetManager#newTheme",
         "android.content.res.AssetManager#deleteTheme",
         "android.content.res.AssetManager#applyThemeStyle",
         "android.content.res.TypedArray#getValueAt",
+        "android.content.res.TypedArray#obtain",
         "android.graphics.BitmapFactory#finishDecode",
+        "android.graphics.Typeface#getSystemFontConfigLocation",
         "android.os.Handler#sendMessageAtTime",
         "android.os.HandlerThread#run",
         "android.text.format.DateFormat#is24HourFormat",
+        "android.util.Xml#newPullParser",
         "android.view.Choreographer#getRefreshRate",
         "android.view.Display#updateDisplayInfoLocked",
         "android.view.Display#getWindowManager",
@@ -170,6 +174,7 @@
         "android.graphics.DiscretePathEffect",
         "android.graphics.DrawFilter",
         "android.graphics.EmbossMaskFilter",
+        "android.graphics.FontFamily",
         "android.graphics.LayerRasterizer",
         "android.graphics.LightingColorFilter",
         "android.graphics.LinearGradient",
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
index ea3dccc..aea3241 100755
--- a/tools/layoutlib/rename_font/build_font.py
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -15,10 +15,10 @@
 # limitations under the License.
 
 """
-Rename the PS name of all fonts in the input directory and copy them to the
+Rename the PS name of all fonts in the input directories and copy them to the
 output directory.
 
-Usage: build_font.py /path/to/input_fonts/ /path/to/output_fonts/
+Usage: build_font.py /path/to/input_fonts1/ /path/to/input_fonts2/ /path/to/output_fonts/
 
 """
 
@@ -30,50 +30,86 @@
 from lxml import etree
 import shutil
 import glob
+from multiprocessing import Pool
+
+# global variable
+dest_dir = '/tmp'
 
 def main(argv):
-  if len(argv) != 2:
-    print "Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/"
-    sys.exit(1)
-  if not os.path.isdir(argv[0]):
-    print argv[0] + "is not a valid directory"
-    sys.exit(1)
-  if not os.path.isdir(argv[1]):
-    print argv[1] + "is not a valid directory"
-    sys.exit(1)
+  if len(argv) < 2:
+    sys.exit('Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/')
+  for directory in argv:
+    if not os.path.isdir(directory):
+      sys.exit(directory + ' is not a valid directory')
+  global dest_dir
+  dest_dir = argv[-1]
+  src_dirs = argv[:-1]
   cwd = os.getcwd()
-  os.chdir(argv[1])
+  os.chdir(dest_dir)
   files = glob.glob('*')
   for filename in files:
     os.remove(filename)
   os.chdir(cwd)
-  for filename in os.listdir(argv[0]):
-    if not os.path.splitext(filename)[1].lower() == ".ttf":
-      shutil.copy(os.path.join(argv[0], filename), argv[1])
-      continue
-    print os.path.join(argv[0], filename)
-    old_ttf_path = os.path.join(argv[0], filename)
+  input_fonts = list()
+  for src_dir in src_dirs:
+    for dirname, dirnames, filenames in os.walk(src_dir):
+      for filename in filenames:
+          input_path = os.path.join(dirname, filename)
+          extension = os.path.splitext(filename)[1].lower()
+          if (extension == '.ttf'):
+            input_fonts.append(input_path)
+          elif (extension == '.xml'):
+            shutil.copy(input_path, dest_dir)
+      if '.git' in dirnames:
+          # don't go into any .git directories.
+          dirnames.remove('.git')
+  # Create as many threads as the number of CPUs
+  pool = Pool(processes=None)
+  pool.map(convert_font, input_fonts)
+
+
+class InvalidFontException(Exception):
+  pass
+
+def convert_font(input_path):
+  filename = os.path.basename(input_path)
+  print 'Converting font: ' + filename
+  # the path to the output file. The file name is the fontfilename.ttx
+  ttx_path = os.path.join(dest_dir, filename)
+  ttx_path = ttx_path[:-1] + 'x'
+  try:
     # run ttx to generate an xml file in the output folder which represents all
     # its info
-    ttx_args = ["-d", argv[1], old_ttf_path]
+    ttx_args = ['-q', '-d', dest_dir, input_path]
     ttx.main(ttx_args)
-    # the path to the output file. The file name is the fontfilename.ttx
-    ttx_path = os.path.join(argv[1], filename)
-    ttx_path = ttx_path[:-1] + "x"
     # now parse the xml file to change its PS name.
     tree = etree.parse(ttx_path)
     encoding = tree.docinfo.encoding
     root = tree.getroot()
     for name in root.iter('name'):
       [old_ps_name, version] = get_font_info(name)
-      new_ps_name = old_ps_name + version
-      update_name(name, new_ps_name)
+      if old_ps_name is not None and version is not None:
+        new_ps_name = old_ps_name + version
+        update_name(name, new_ps_name)
     tree.write(ttx_path, xml_declaration=True, encoding=encoding )
     # generate the udpated font now.
-    ttx_args = ["-d", argv[1], ttx_path]
+    ttx_args = ['-q', '-d', dest_dir, ttx_path]
     ttx.main(ttx_args)
-    # delete the temp ttx file.
+  except InvalidFontException:
+    # In case of invalid fonts, we exit.
+    print filename + ' is not a valid font'
+    raise
+  except Exception as e:
+    print 'Error converting font: ' + filename
+    print e
+    # Some fonts are too big to be handled by the ttx library.
+    # Just copy paste them.
+    shutil.copy(input_path, dest_dir)
+  try:
+    # delete the temp ttx file is it exists.
     os.remove(ttx_path)
+  except OSError:
+    pass
 
 def get_font_info(tag):
   ps_name = None
@@ -85,19 +121,17 @@
       if namerecord.attrib['nameID'] == '6':
         if ps_name is not None:
           if not sanitize(namerecord.text) == ps_name:
-            sys.exit('found multiple possibilities of the font name')
+            raise InvalidFontException('found multiple possibilities of the font name')
         else:
           ps_name = sanitize(namerecord.text)
       # nameID=5 means the font version
       if namerecord.attrib['nameID'] == '5':
         if ps_version is not None:
           if not ps_version == get_version(namerecord.text):
-            sys.exit('found multiple possibilities of the font version')
+            raise InvalidFontException('found multiple possibilities of the font version')
         else:
           ps_version = get_version(namerecord.text)
-  if ps_name is not None and ps_version is not None:
-    return [ps_name, ps_version]
-  sys.exit('didn\'t find the font name or version')
+  return [ps_name, ps_version]
 
 
 def update_name(tag, name):
@@ -110,11 +144,11 @@
   return re.sub(r'[^\w-]+', '', string)
 
 def get_version(string):
-  # The string must begin with "Version n.nn "
+  # The string must begin with 'Version n.nn '
   # to extract n.nn, we return the second entry in the split strings.
   string = string.strip()
-  if not string.startswith("Version "):
-    sys.exit('mal-formed font version')
+  if not string.startswith('Version '):
+    raise InvalidFontException('mal-formed font version')
   return sanitize(string.split()[1])
 
 if __name__ == '__main__':
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
index 9a633b4..090ac56 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -36,6 +36,7 @@
     private String mCredentialName;
     private String mUpdateIdentifier;
     private String mSubscriptionUpdateMethod;
+    private WifiEnterpriseConfig mEnterpriseConfig;
     private String mType;
     private String mInnerMethod;
     private String mCertType;
@@ -93,17 +94,15 @@
      * Constructor
      * @param realm Realm of the passpoint credential
      * @param fqdn Fully qualified domain name (FQDN) of the credential
-     * @param config Credential information, must be either EAP-TLS or EAP-TTLS
+     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
      * @see WifiEnterpriseConfig
      */
     public WifiPasspointCredential(String realm, String fqdn, WifiEnterpriseConfig config) {
         mRealm = realm;
         switch (config.getEapMethod()) {
             case WifiEnterpriseConfig.Eap.TLS:
-                // TODO;
-                break;
             case WifiEnterpriseConfig.Eap.TTLS:
-                // TODO;
+                mEnterpriseConfig = new WifiEnterpriseConfig(config);
                 break;
             default:
                 // ignore
@@ -299,11 +298,21 @@
     }
 
     /**
-     * Get EAP method of this Passpoint credential.
-     * @return EAP method, refer to {@link WifiEnterpriseConfig.Eap} for possible return values
+     * Get enterprise config of this Passpoint credential.
+     * @return Enterprise config
+     * @see WifiEnterpriseConfig
      */
-    public int getEapMethod() {
-        return 0;
+    public WifiEnterpriseConfig getEnterpriseConfig() {
+        return new WifiEnterpriseConfig(mEnterpriseConfig);
+    }
+
+    /**
+     * Set enterprise config of this Passpoint credential.
+     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
+     * @see WifiEnterpriseConfig
+     */
+    public void setEnterpriseConfig(WifiEnterpriseConfig config) {
+        // TODO
     }
 
     /** @hide */
@@ -316,10 +325,7 @@
         return mCertSha256Fingerprint;
     }
 
-    /**
-     * Get the user name of this Passpoint credential, for EAP-TTLS only.
-     * @return user name
-     */
+    /** @hide */
     public String getUserName() {
         return mUsername;
     }
@@ -345,31 +351,17 @@
         return mMnc;
     }
 
-    /**
-     * Get the CA root certificate path of this Passpoint credential.
-     * @return CA root certificate path
-     */
+    /** @hide */
     public String getCaRootCertPath() {
         return mCaRootCert;
     }
 
-    /**
-     * Get the client certificate path of this Passpoint credential, for EAP-TLS only.
-     * @return client certificate path
-     */
+    /** @hide */
     public String getClientCertPath() {
         return mClientCert;
     }
 
     /**
-     * Set credential information of this Passpoint credential.
-     * @param config Credential information, must be either EAP-TLS or EAP-TTLS
-     */
-    public void setCredential(WifiEnterpriseConfig config) {
-        // TODO
-    }
-
-    /**
      * Get the realm of this Passpoint credential.
      * @return Realm
      */